예로 가계부 앱을 보면 요즘 카드/체크카드 결제 내역을 사용자가 직접 입력하는 경우는 거의 없습니다.
SMS로 결제 통보가 오면, 가계부 앱에서 이를 자동으로 등록하며,
사용 내역 같은 정보만 사용자가 다시 수정하는 정도입니다.
그럼 가계부 앱은 어떻게 SMS을 읽고서 그것을 자신의 DB/저장소에 등록할 수 있는 것일까요?
이 시나리오에 대해 다음 두 가지 포인트를 생각해볼 수 있습니다.
2번의 경우는 String 파싱/정규표현식과 관련된 내용으로 여기서 다루진 않으며,
1번 SMS 문자를 앱에서 읽는 부분에 대해서만 다룹니다.
우선 본 내용의 구현 과정을 간단히 요약하면 다음과 같습니다.
SMS 메시지 본문에 접근해야 하므로, 이는 권한이 필요한 부분입니다.따라서 하기와 같이 AndroidManifest.xml 파일에 필요한 권한을 선언해야 합니다.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.test">
...
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
...
</manifest>
SMS 가 도착할 경우 안드로이드 시스템 상 Broadcast Event가 발송되며,
이는 BroadcastReceiver를 통해 수신할 수 있습니다.
물론 BroadcastReceiver는 이외 다른 여러 이벤트들을 수신할 수 있습니다.
여기서는 SMS 수신 관련 이벤트가 필요하므로,
SMS 수신 이벤트를 받을 수 잇는 BroadcastRecevier를 구현하도록 하겠습니다.
BroadcastReceiver 클래스는 abstract class (추상 클래스)로서 이를 상속받아 직접 구현해 주어야 합니다.
https://developer.android.com/reference/android/content/BroadcastReceiver.html
public class SMSReceiver extends BroadcastReceiver {
private static final String TAG = "SMSReceiver";
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "BroadcastReceiver Received");
if ("android.provider.Telephony.SMS_RECEIVED".equals(intent.getAction())) {
Bundle bundle = intent.getExtras();
Object[] messages = (Object[])bundle.get("pdus");
SmsMessage[] smsMessage = new SmsMessage[messages.length];
for(int i = 0; i < messages.length; i++) {
smsMessage[i] = SmsMessage.createFromPdu((byte[])messages[i]);
}
String message = smsMessage[0].getMessageBody().toString();
Log.d(TAG, "SMS Message: " + message);
}
}
}
SMS 문자 수신에 대한 이벤트는 다음과 같은 문자열 Action으로 전달되며,
onReceive의 intent에서 확인할 수 있습니다.
"android.provider.Telephony.SMS_RECEIVED"
SmsMessage 객체에서는 Message 외에 발신자 정보,
수신 시간 등 여러 정보를 얻을 수 있습니다.
자세한 것은 Reference 문서를 참조하기 바랍니다.
https://developer.android.com/reference/android/telephony/SmsMessage.html
이제 구현한 BroadcastReceiver 클래스를 등록해주어야 합니다.
BroadcastReceiver를 등록하는 방법에는 java code로 프로그램적으로 등록하는 방법과
Manifest를 이용하는 방법이 있는데,
여기서는 Manifest를 이용하여 등록하겠습니다.
방법은 간단합니다.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.test">
...
<application
...
<receiver android:name=".sms.SMSReceiver">
<intent-filter android:priority="10000">
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
</application>
</manifest>
이제 문자를 보내보고 잘 받아지는지 확인합시다!
1. 앱이 현재 화면에 onCreate되어 있는 상황에서만 수신이 가능한걸까?
만약 앱이 종료된 상태에서 문자가 왔을 때 이를 처리할 수 있을까?
이를 위해서는 Background에서 동작하는 별도 Service를 구현해야 할까?
> 다행히도 그럴 필요 없습니다.
이미 위 예제와 같이 구현했다면 BroadcastReceiver는 Background에서도 수신하여 동작합니다.
2. 위와 같이 구현했는데 문자 수신하여도 BroadcastReceiver.onReceive() 메서드가 불리지 않는 경우
> Permission 이슈일 수 있습니다.
Android 6.0 (API level 23) 부터는 앱 설치 시가 아닌 앱이 실행되는 도중에 앱에 권한을 부여하도록 변경되었습니다.
이런 경우라면 Step 1의 권한 부여로는 부족합니다.
자세한 내용은 아래 링크를 확인하시기 바랍니다.
https://developer.android.com/training/permissions/requesting.html?hl=ko
SMS로 결제 통보가 오면, 가계부 앱에서 이를 자동으로 등록하며,
사용 내역 같은 정보만 사용자가 다시 수정하는 정도입니다.
그럼 가계부 앱은 어떻게 SMS을 읽고서 그것을 자신의 DB/저장소에 등록할 수 있는 것일까요?
이 시나리오에 대해 다음 두 가지 포인트를 생각해볼 수 있습니다.
1. SMS 문자가 오면 이를 가계부 앱에서 이벤트로 받고, 그 내용을 볼 수 있다.
2. 그 내용을 적절히 분석/파싱하여 가계부 DB/저장소 내 데이터 스키마에 맞게 변환하여 저장한다.
2번의 경우는 String 파싱/정규표현식과 관련된 내용으로 여기서 다루진 않으며,
1번 SMS 문자를 앱에서 읽는 부분에 대해서만 다룹니다.
우선 본 내용의 구현 과정을 간단히 요약하면 다음과 같습니다.
1. SMS 를 받을 수 있도록 권한 부여
2. BroadcastReceiver 클래스 구현
3. 구현한 BroadcastReceiver 클래스 등록
1. SMS를 받을 수 있도록 권한 부여
SMS 메시지 본문에 접근해야 하므로, 이는 권한이 필요한 부분입니다.따라서 하기와 같이 AndroidManifest.xml 파일에 필요한 권한을 선언해야 합니다.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.test">
...
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
...
</manifest>
2. BroadcastReceiver 클래스 구현
SMS 가 도착할 경우 안드로이드 시스템 상 Broadcast Event가 발송되며,
이는 BroadcastReceiver를 통해 수신할 수 있습니다.
물론 BroadcastReceiver는 이외 다른 여러 이벤트들을 수신할 수 있습니다.
여기서는 SMS 수신 관련 이벤트가 필요하므로,
SMS 수신 이벤트를 받을 수 잇는 BroadcastRecevier를 구현하도록 하겠습니다.
BroadcastReceiver 클래스는 abstract class (추상 클래스)로서 이를 상속받아 직접 구현해 주어야 합니다.
https://developer.android.com/reference/android/content/BroadcastReceiver.html
public class SMSReceiver extends BroadcastReceiver {
private static final String TAG = "SMSReceiver";
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "BroadcastReceiver Received");
if ("android.provider.Telephony.SMS_RECEIVED".equals(intent.getAction())) {
Bundle bundle = intent.getExtras();
Object[] messages = (Object[])bundle.get("pdus");
SmsMessage[] smsMessage = new SmsMessage[messages.length];
for(int i = 0; i < messages.length; i++) {
smsMessage[i] = SmsMessage.createFromPdu((byte[])messages[i]);
}
String message = smsMessage[0].getMessageBody().toString();
Log.d(TAG, "SMS Message: " + message);
}
}
}
SMS 문자 수신에 대한 이벤트는 다음과 같은 문자열 Action으로 전달되며,
onReceive의 intent에서 확인할 수 있습니다.
"android.provider.Telephony.SMS_RECEIVED"
SmsMessage 객체에서는 Message 외에 발신자 정보,
수신 시간 등 여러 정보를 얻을 수 있습니다.
자세한 것은 Reference 문서를 참조하기 바랍니다.
https://developer.android.com/reference/android/telephony/SmsMessage.html
3. 구현한 BroadcastReceiver 클래스 등록
이제 구현한 BroadcastReceiver 클래스를 등록해주어야 합니다.
BroadcastReceiver를 등록하는 방법에는 java code로 프로그램적으로 등록하는 방법과
Manifest를 이용하는 방법이 있는데,
여기서는 Manifest를 이용하여 등록하겠습니다.
방법은 간단합니다.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.test">
...
<application
...
<receiver android:name=".sms.SMSReceiver">
<intent-filter android:priority="10000">
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
</application>
</manifest>
이제 문자를 보내보고 잘 받아지는지 확인합시다!
PS. 추가 사항
1. 앱이 현재 화면에 onCreate되어 있는 상황에서만 수신이 가능한걸까?
만약 앱이 종료된 상태에서 문자가 왔을 때 이를 처리할 수 있을까?
이를 위해서는 Background에서 동작하는 별도 Service를 구현해야 할까?
> 다행히도 그럴 필요 없습니다.
이미 위 예제와 같이 구현했다면 BroadcastReceiver는 Background에서도 수신하여 동작합니다.
2. 위와 같이 구현했는데 문자 수신하여도 BroadcastReceiver.onReceive() 메서드가 불리지 않는 경우
> Permission 이슈일 수 있습니다.
Android 6.0 (API level 23) 부터는 앱 설치 시가 아닌 앱이 실행되는 도중에 앱에 권한을 부여하도록 변경되었습니다.
이런 경우라면 Step 1의 권한 부여로는 부족합니다.
자세한 내용은 아래 링크를 확인하시기 바랍니다.
https://developer.android.com/training/permissions/requesting.html?hl=ko
앱이 종료된 상태에서는 onReceive가 호출되지 않는데 어떻게 하신거죠?
답글삭제커스텀 안드로이드 문제인것 같네요.
삭제위 질문은 무시해주십시요
sms 가 아닌 lms(긴문자)의 경우에는 작동을 안하는데요, 긴문자의 경우에도 처리하는 방법이 있을까요?
답글삭제구글링하면 LMS 에 대한 예시코드 나올 겁니다.
삭제