Android 4대 컴포넌트 액티비티(Activity), 서비스(Service), 방송 수신자(BroadCast Receiver), 콘텐츠 제공자(Content Provider) 중 한개인 BroadcastReceiver 의 기초에 대해서 공부해보았습니다.
이번에 진행한 예제는 SMS 수신시 새로운 Activity에 송신자의 번호(address) 와 내용(content)를 보여주는 예제이다.
먼저 SMS메시지를 수신하는 SmsReceiver class 전문이다.
package com.example.reciever;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.telephony.SmsMessage;
import android.util.Log;
public class SmsReceiver extends BroadcastReceiver {
private static final String TAG = "SmsReviever";
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "onReceive 호출됨");
Bundle bundle = intent.getExtras();
SmsMessage[] messages = parseSmsMessage(bundle);
if(messages != null && messages.length>0){
String sender = messages[0].getOriginatingAddress();
String contents = messages[0].getMessageBody();
Log.d(TAG, "sender :"+sender +" contents :" +contents );
sendToActivity(context,sender,contents);
}
}
private void sendToActivity(Context context, String sender, String contents) {
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);
context.startActivity(intent);
}
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;
}
}
리시버 클래스를 만들게되면 AndroidManifast.xml 에 해당 Receiver가 등록되어있는데마지막에 <intent-filter> 를 추가하여 아래처럼 입력해주자.Telephony.SMS_RECEIVED 는 SMS수신에 대한 Intent를 받겠다는 필터를 걸어주는 것이다.해당 필터를 등록하지않으면 리시버는 어떤걸 수신하게될지모르게된다.. (작동안된다.)
<receiver
android:name=".SmsReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
BroadcastReceiver를 상속받는 이 클래스는 수신받았을때의 작동하는 onReceive 함수를 꼭 오버라이드 해주어야한다.
여기서 Context 객체와 Intent 객체를 받아서 Activity로 넘겨준다.
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "onReceive 호출됨");
Bundle bundle = intent.getExtras();
SmsMessage[] messages = parseSmsMessage(bundle);
if(messages != null && messages.length>0){
String sender = messages[0].getOriginatingAddress();
String contents = messages[0].getMessageBody();
Log.d(TAG, "sender :"+sender +" contents :" +contents );
sendToActivity(context,sender,contents);
}
}
여기서 onReceive가 받은 Bundle 객체를 SmsMessage 객체로 파싱해주기위해 함수를 만들어준다.
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;
}
여기서 bundle.get 에 들어가는 key 값인 pdus는 SmsMessage 데이터를 처리하는 국제표준 프로토콜로써
pdus안에 SmsMessage데이터 관련된 내용이 들어가 있다고 생각하면 된다.
다만 이를 Object 객체의 배열로 반환하기 때문에 objs로 받아준다.
그리고 받아온 objs의 길이만큼의 SmsMessage[] 배열을 생성한다.
그리고 for문을 돌려 messages에 objs에 있는 메시지 객체를 선별하여 담아준다.
여기서 Build.VERSION.SDK_INT 는 현재 단말기의 SDK(OS) 버전을 알려준다.
만약 M(마시멜로우, 6) 이상이라면 .createFromPdu 함수에 문자포맷 방식까지 인자로 넣어주어야 한다.
마지막으로 이렇게 SmsMessage 객체를 담은 messages 를 반환해준다.
파싱된 SmsMessage를 Intent에 담아 Activity 로 전달해주는 sendToActivity 함수를 만들어준다.
context.startActivity 로 intent 전달 ~
private void sendToActivity(Context context, String sender, String contents) {
Intent intent = new Intent(context, MainActivity.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);
context.startActivity(intent);
}
다음은 화면을 표시해주는 MainActivity 전문이다..
package com.example.reciever;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import com.pedro.library.AutoPermissions;
import com.pedro.library.AutoPermissionsListener;
public class MainActivity extends AppCompatActivity implements AutoPermissionsListener {
private static final String TAG = "MainActivity";
TextView textView7;
TextView textView8;
TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView7 = findViewById(R.id.textView7);
textView8 = findViewById(R.id.textView8);
textView = findViewById(R.id.textView);
textView7.setText("발신인 : ");
textView8.setText("수신인 : ");
Log.d(TAG, "ontextview : ");
AutoPermissions.Companion.loadAllPermissions(this,101);
Intent intent = getIntent();
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
processIntent(intent);
}
private void processIntent(Intent intent) {
if (intent != null){
String sender = intent.getStringExtra("sender");
String contents= intent.getStringExtra("contents");
textView7.setText(sender);
textView8.setText(contents);
textView.setText(contents);
}
}
@Override
public void onDenied(int requestCode, @NonNull String[] permissions) {
Log.d(TAG, "Permissions : "+ permissions.length);
}
@Override
public void onGranted(int requestCode, @NonNull String[] permissions) {
Log.d(TAG, "not Permissions : "+ permissions.length);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
AutoPermissions.Companion.parsePermissions(this,requestCode,permissions,this);
}
}
간단하다.. TextView 3개를 만들어서
하나는 제목, 한개는 발신인 번호, 한개는 내용을 표시해준다.
여기서 주의해야할 점은 클래스에 implements AutoPermissionsListener 이다..
SMS 수신같은 경우는 Permission 이 필요한데 이를위해서 권한요청을 하게하는 라이브러리인 AutoPermissions을 사용해주어야한다.
다만 이는 외부 라이브러리 이기때문에 build.gradle에 dependencies 내부에 하기와 같이 선언을 해주어야한다.
implementation 'com.github.pedroSG94:AutoPermissions:1.0.3'
또한 외부 라이브러리 사용을 위해 Settings.gradle 에도 일부 내용을 추가해주어야한다.
dependencyResolutionManagement 내부에 하기처럼 추가해주자
repositories {
google()
mavenCentral()
jcenter() // Warning: this repository is going to shut down soon
maven { url "https://jitpack.io" }
}
그리고 상단의 Sync Now를 클릭해주면 .. 알아서 외부 라이브러리를 다운받는다.
다시 MainActivity로 돌아와서 AutoPermissionsListener 를 implements 했기때문에 몇가지 함수를 오버라이드 해준다.
onDenied는 permission이 거절당했을때, onGranted는 permission을 수락받았을때 각각 동작한다.
그리고 최종적으로 onRequestPermissionsResult는 권한 요청에 대한 결과를 아규먼트로 받을 수 있습니다.
그리고 onNewIntent로 Intent가 발생되었을때 동작하게끔 processIntent 함수를 정의해준다.
private void processIntent(Intent intent) {
if (intent != null){
String sender = intent.getStringExtra("sender");
String contents= intent.getStringExtra("contents");
textView7.setText(sender);
textView8.setText(contents);
textView.setText(contents);
}
}
processIntent에서는.. 받아온 intent에서 sender와 contents를 텍스트뷰에 셋 !
끝입니다 ^^
'개발일지' 카테고리의 다른 글
Jetson과 NVRAM 간의 SPI 통신 [1] (1) | 2024.10.07 |
---|---|
YOCTO Project 란 ? (4) | 2024.09.26 |
임베디드 S/W 공부 (0) | 2022.11.25 |
C++ STL 정렬되지 않은 셋과 맵 (0) | 2022.11.23 |
C++ STL 멀티셋(multiset) 과 멀티맵 (multimap) (2) | 2022.11.23 |