티스토리 뷰

안녕하세요 ㅎ

원래는 2014년 처음에 올리려고 했는데 요즘 심한 감기에 걸려서 쿨럭

이번강좌부터는 조금씩 어려워 지고 있습니다

잘 따라와 주시고 이해가 안되는 부분은 아 그런가 보다~ 라고 생각하시는게 나을때가 많을겁니다 ㅎㅎ...


24. Broadcast Receiver로 문자(SMS) 수신해보자

24-1 Broadcast Receiver란?

브로드 캐스트(브로드캐스트리시버, BroadcastReceiver)란 과연 무엇일까요?


broadcast : 방송하다

receiver : 수신기(수신하다)

각각 이러한 뜻을 가지고 있는데요


합쳐보면 "방송을 수신한다" 라는 뜻이 됩니다



안드로이드에서는 어떠한 이벤트(활동)를 스피커에 대고 방송을 합니다

"핸드폰 화면이 꺼졌어요~"

그럼 브로드캐스트리시버가 이 방송을 듣습니다

"아 화면이 꺼졌다, 이러한 코드를 실행해야지"

이러한 원리로 작동이 되는겁니다



즉, 안드로이드에서 보내주는 이벤트를 수신해서 처리하는 곳이 바로 브로드캐스트리시버 입니다


그리고 브로드캐스트리시버는 우선순위에 따라 순차적으로 메세지가 전달됩니다

가장 우선순위가 높은 리시버에게 이벤트를 보내고, 그아래, 그아래.....으로 전달됩니다


이 BroadcastReceiver는 정적 리시버와 동적 리시버로 나눌수 있는데요

정적 리시버는 AndroidManifest.xml에 등록하며, 동적 리시버는 매니페스트에 등록하지 않습니다




24-2 Broadcast Receiver에서 받을수 있는 이벤트는 무엇이 있나요?

브로드캐스트에서 받을수 있는 액션이 무엇이 있는지 조금만 살펴보겠습니다


ACTION_BOOT_COMPLETED

부팅이 끝났을 때 (RECEIVE_BOOT_COMPLETED 권한등록 필요)


ACTION_CAMERA_BUTTON

카메라 버튼이 눌렸을 때


ACTION_DATE_CHANGED

ACTION_TIME_CHANGED

폰의 날짜, 시간이 수동으로 변했을때 (설정에서 수정했을때)


ACTION_SCREEN_OFF

ACTION_SCREEN_ON

화면 on, off


ACTION_AIRPLANE_MODE_CHANGED

비행기 모드


ACTION_BATTERY_CHANGED

ACTION_BATTERY_LOW

ACTION_BATTERY_OKAY

배터리 상태변화


ACTION_PACKAGE_ADDED

ACTION_PACKAGE_CHANGED

ACTION_PACKAGE_DATA_CLEARED

ACTION_PACKAGE_INSTALL

ACTION_PACKAGE_REMOVED

ACTION_PACKAGE_REPLACED

ACTION_PACKAGE_RESTARTED

어플 설치/제거


ACTION_POWER_CONNECTED

ACTION_POWER_DISCONNECTED

충전 관련


ACTION_REBOOT

ACTION_SHUTDOWN

재부팅/종료


ACTION_TIME_TICK

매분마다 수신


android.provider.Telephony.SMS_RECEIVED

sms 수신 (RECEIVE_SMS 권한 필요)

(전체중 극히 일부)


이중에서 굵은 표시가 되어 있는 부팅완료, 화면 on,off, 문자 수신을 가지고 예제를 만들어 보도록 하겠습니다




24-3 java파일 만들기

먼저 java파일을 만들어 줍시다

이 파일이 우리가 수신한 액션을 처리하는 브로드캐스트리시버 파일이 될것입니다

이름은 Broadcast.java입니다


import android.content.BroadcastReceiver;

import android.content.Context;

import android.content.Intent;


public class Broadcast extends BroadcastReceiver {


    @Override

    public void onReceive(Context context, Intent intent) {

    // 수신한 액션을 이 onReceive메소드에서 처리하게 됩니다

    }

}

달랑 메소드 하나만 있습니다

저 onReceive메소드에서 액션을 수신하여 처리할 코드를 입력해 주면 되는데요


액션이 하나라면 문제가 없지만 2개이상일때는 각각 구분해야 할 필요가 있습니다

intent.getAction()

으로 어떤 액션인지 알수 있습니다


예를들어 화면 on, off, 부팅 완료, sms수신의 경우

if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())){

    // 부팅완료

}

if (Intent.ACTION_SCREEN_ON == intent.getAction()) {

    // 화면 켜짐

}

if (Intent.ACTION_SCREEN_OFF == intent.getAction()) {

    // 화면 꺼짐

}

if ("android.provider.Telephony.SMS_RECEIVED".equals(intent.getAction())) {

    // sms 수신

}

이렇게 if문을 통해 구현해 주시면 됩니다 (이때 ==이나 equals나 상관이 없다고합니다만 잘 모르겠내요)


참고로 Intent.ACTION_BOOT_COMPLETED이나 "android.intent.action.BOOT_COMPLETED"이나 같다고 합니다만 전자는 java에서, 후자는 xml에서 자주 보이는군요



이제 각각의 액션을 구분할수 있게 되었습니다

로그를 찍어서 한번 잘 작동하는지 보겠습니다

Log.d("onReceive()","부팅완료");

Log.d("onReceive()","스크린 ON");

Log.d("onReceive()","스크린 OFF");

Log.d("onReceive()","문자가 수신되었습니다");

각각 if문안에 넣어주세요



그다음 문자 수신의 경우는 누가 보냈는지와, 어떤 내용인지, 언제 수신했는지등의 정보를 알아야 합니다

이것은 일단 맨 아래에서 설명해 봅시다


참고로 우선순위가 낮은 브로드캐스트리시버가 수신을 못하게 하는 방법은

abortBroadcast();

를 사용하시면 됩니다


이제 매니페스트 파일에 등록해 봅시다




24-4 AndroidManifest.xml에 등록하자 (정적 등록)

정적 등록이라는건 한번 등록하면 수정이 안됩니다 (무조건 수신)

그러나 java에서 등록하면 xml보다 유동적으로 등록/해제가 가능합니다


사실 브로드캐스트는 등록할 필요가 그닥 없으며, xml에 등록을 해도 받지 못하는 액션도 있습니다

그런 액션은 동적으로 등록해야 합니다 (24-5 참조)



한번 등록해 봅시다

<receiver android:name ="whdghks913.tistory.examplebroadcastreceiver.Broadcast">

    <intent-filter android:priority="9999">

        <action android:name="android.intent.action.BOOT_COMPLETED"/>

        <action android:name="android.provider.Telephony.SMS_RECEIVED" /> 

    </intent-filter>

</receiver>

receiver를 등록하였습니다


저기서 android:priority는 우선순위로, 숫자가 높을수록 우선순위가 높습니다

우선순위가 높은 리시버 부터 순차적으로 메세지가 전달됩니다


그런대 화면 on, off는 없내요?

그것은 위에서 말했드시 일부 액션은 xml에 등록해도 액션을 받을수 없습니다

그러므로 아래에서 살펴볼 registerReceiver()메소드를 이용해 등록해야만 합니다


마지막으로 부팅완료와 sms수신은 권한이 필요합니다

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

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




24-5 registerReceiver()로 등록하자 (동적 등록)

24-4에서 등록하지 못한 Screen on과 off는 동적으로 java파일에서만 등록이 가능한 액션의 대표적인 예입니다

이번에는 동적으로 등록해 보겠습니다


MainActivity.java를 열어주세요

BroadcastReceiver myReceiver = new Broadcast();

Button이나 TextView처럼 추가해 주시면 됩니다

굵게 표시한 Broadcast()는 java파일의 이름입니다


그다음 onCreate()에는

IntentFilter intentFilter = new IntentFilter(Intent.ACTION_SCREEN_ON);

intentFilter.addAction(Intent.ACTION_SCREEN_OFF);

intentFilter.addAction(Intent.ACTION_BOOT_COMPLETED);

intentFilter.addAction("android.provider.Telephony.SMS_RECEIVED");


registerReceiver(myReceiver, intentFilter);

Log.d("onCreate()","브로드캐스트리시버 등록됨");

를 입력해 봅시다

IntentFilter를 통해 액션을 등록한다음, registerReceiver()로 리시버를 등록하고 있습니다


마지막으로 어플을 종료할때 호출되는 onDestroy()메소드를 만들어 액티비티가 종료되면 등록을 해제합시다

@Override

protected void onDestroy() {

    super.onDestroy();

    unregisterReceiver(myReceiver);

    Log.d("onDestory()","브로드캐스트리시버 해제됨");

}

unregisterReceiver()로 등록을 해제할수 있습니다


이렇게 등록된 리시버는 등록한 액티비티가 사라지거나 하면 등록이 해제되는 단점이 있어 죽지 않는 서비스에서 등록합니다




24-6 문자 내용 수신 코드

아래는 문자 내용을 수신하는 코드입니다

// SMS 메시지를 파싱합니다.

Bundle bundle = intent.getExtras();

Object messages[] = (Object[])bundle.get("pdus");

SmsMessage smsMessage[] = new SmsMessage[messages.length];


for(int i = 0; i < messages.length; i++) {

    // PDU 포맷으로 되어 있는 메시지를 복원합니다.

    smsMessage[i] = SmsMessage.createFromPdu((byte[])messages[i]);

}


// SMS 수신 시간 확인

Date curDate = new Date(smsMessage[0].getTimestampMillis());

Log.d("문자 수신 시간", curDate.toString());


// SMS 발신 번호 확인

String origNumber = smsMessage[0].getOriginatingAddress();


// SMS 메시지 확인

String message = smsMessage[0].getMessageBody().toString();

Log.d("문자 내용", "발신자 : "+origNumber+", 내용 : " + message);

그러나 아직 어려우므로 이해하지 말고 그렇구나 하고 넘어갑시다 ㅎ

출처 : http://android-town.org/




24-7 완성!!

자, 이제 모든것이 완성되었습니다

그럼 작동을 확인해 보겠습니다


로그를 찍어보면 정상 작동하고 있다는 것이 나타납니다 ㅎㅎ



이번 강좌는 뭔가 횡설수설한 느낌이 강하네요;

오타가 많을거 같습니다

발견하시면 알려주세요 ㅎ




ExampleBroadcastReceiver.zip

댓글
  • 헤이야수 좋은글 잘 보고 갑니다!!! 2014.01.03 11:10 신고
  • Favicon of http://itmir.tistory.com Mir(whdghks913) 방문해 주셔서 감사합니다 ㅎㅎ 2014.01.06 19:23 신고
  • 초보 감사합니다!! 2014.01.20 20:33 신고
  • 초보 재미있게 보고있습니다.

    헌데 잘모르겠어서 예제소스를 기다리고 있는데 안올라오네요 ㅠ 소스좀 올려주세요!
    2014.02.14 12:35 신고
  • Favicon of http://itmir.tistory.com Mir(whdghks913) 앗 죄송합니다 지금 올렸습니다^^ 2014.02.14 13:34 신고
  • 초보 갑사합니다! ^^ 2014.02.14 18:05 신고
  • 오앵무 브로드캐스트 클래스를 타 클래스 안에 넣어서 사용하고 싶은데 registerReceiver의 첫 번째 인자에는 무엇을 넣어야하나요?ㅜㅜ 그대로 myReceiver를 넣어봤는데 에러가 나네요...ㅠㅠㅠ 2014.02.21 17:52 신고
  • Favicon of http://itmir.tistory.com Mir(whdghks913) 동적 등록 부분을 다시한번 읽어보시면 아실것 같습니다 2014.02.21 19:23 신고
  • Favicon of http://itmir.tistory.com Mir(whdghks913) 첫번째 인자에는 BroadcastReceiver가 들어갑니다 2014.02.21 19:24 신고
  • 오앵무 감사합니다.
    그런데 BroadcastReceiver myReceiver=new Broadcast();에서
    new Broadcast() 자리에 뭘 넣어야 하는지 아무리 생각해도 모르겠어요ㅠㅠㅠ 온갖 것을 다 넣어봤는데도 오류가 나네요ㅠㅠ
    2014.02.24 09:45 신고
  • Favicon of http://itmir.tistory.com Mir(whdghks913) 클래스 파일의 이름입니다

    이 예제에서 브로드캐스트 파일의 이름이 myReceiver이기 때문에 new myReceiver이라고 쓴것입니다

    public class (class이름) {
    // 코드
    }
    2014.02.24 09:49 신고
  • 오앵무 Broadcast 클래스를 아무런 수정 없이 통째로 다른 클래스 안에 넣었는데 브로드캐스트리시버 등록하는 부분과 해제하는 부분에서 자꾸 멈춰요ㅠ.ㅠ
    계속해서 질문 드려서 죄송합니다ㅠㅠ
    2014.02.24 09:53 신고
  • Favicon of http://itmir.tistory.com Mir(whdghks913) 클린 한번 해보시겠어요?

    자바는 .java파일 소스를 다른 파일에 넣어도 문제가 발생하지 않는대
    (package부분은 지워주셔야 합니다)

    오류가 나는 부분을 검색해보시고 그래도 안된다면 지금은 클래스를 분리하시는걸 추천드립니다
    2014.02.24 09:55 신고
  • 오앵무 클린도 수백 번 해보고 패키지 부분도 지웠는데 이러네요ㅠㅠ
    DB를 사용하려고 일부러 합친건데 계속 에러가 나서 골치예요ㅠㅠㅠ
    답변 정말정말 감사합니다. 좋은하루 보내세요!
    2014.02.24 09:58 신고
  • 오앵무 public과 class사이에 static을 넣었더니 해결 되었어요;ㅅ; 2014.02.24 10:53 신고
  • Favicon of http://itmir.tistory.com Mir(whdghks913) static이라면 new선언안해도 사용가능하도록 메모리에 미리 올려두는건대

    혹시 브로드캐스트를 등록하는 부분이 static이라던가 인가요??
    2014.02.24 10:57 신고
  • 오앵무 브로드캐스트 등록하는 부분은 static 아니에요!
    미르님이 올려주신 코드 그대로 가져다 쓰고 public과 class 사이에 static 넣어준 것 밖에 바꾼 거 없어요!
    2014.02.24 11:51 신고
  • 용이 미르님이 안녕하세요
    갤3 에 설치가능한 갤4런쳐 문의좀 드릴려구요
    얼마전에도 문의 드렸구요
    설치 후 다른건 다 작동되는데 위젯이 안되는되요.
    위젯 가능하게 수정가능 하실까 해서요.
    물론 지금처럼 노루팅 순정 갤3 에 일반앱 처럼 설치가능하게요. 루팅해라 system 으로 넣어라 이런 말씀은 하지 마세요. 제가 루팅안하고도 가능하다고 생각하는 이유는 구글마켓에 일반 설치형 테마나 런처들 보면 apk설치만 하고 따로 시스템 폴더 안건드리고도 위젯 잘 되잖아요.
    이 경우도 마찬가지인데 위젯만 안되니..어디 조금 수정만 하면 가능할듯 해서요
    이것땜에 3주째 고민중입니다 ㅜ
    터치위즈 전용 위젯은 안되도 상관없고요
    uccw같은 일반 마켓용 위젯만이라도 가능하게 수정 안될까요?
    2014.02.24 12:32 신고
  • 용이 저한텐 꼭 필요해서요
    부득이 하게 마지막 심정으로 미르님께 요청드려 봅니다.
    2014.02.24 12:37 신고
  • 용이 http://m.cafe.naver.com/develoid/376086
    참고로 이것도 갤4 비슷한 apk설치형 런처인데
    이건 시스템 안건드리고도 설치만 하고도 위젯 잘되거든요..
    2014.02.24 12:41 신고
  • 용이 제 생각엔 갤4런처 설치하려고 터치하면 나오는 설치화면에서 맨 아래로 내려보시면 물음표 하고 안드로이드 로봇 나오는 부분 permission write, read 이것땜에 그런거 같아요
    구글마컷에서 받은 런처나 테마는 이게 없더라구요
    2014.02.24 14:11 신고
  • 용이 근데 이상한건 위젯 중에 바로전화거리, 사용설명서 위젯은 되요.이것만 됩니다 ㅜ 2014.02.24 16:18 신고
  • 오앵무 정말 죄송한데 혹시 제 프로젝트 에러 잡아주실 수 있으신가요?
    탭 액티비티로 하고 있는데 두 탭은 정상적으로 작동하고 두 탭은 에러가 발생해요ㅠㅠ
    에러 발생하는 두 탭이 하나는 차트를 그리는 거고 하나는 브로드캐스트인데
    엉뚱하게 setText나 setonclicklistener 에서 에러예요.ㅠㅠ
    그리고 로그에는 Unable to start activity ComponentInfo 라고 나옵니다.
    매니페스트나 그런 건 다 등록했어요!
    2014.02.25 14:43 신고
  • Favicon of http://itmir.tistory.com Mir(whdghks913) 브로드캐스트는 Context를 사용해야 하는 경우가 있어요

    저 오류는 레이아웃을 잘못 설정했을때 생기는 오류라고 알고있습니다
    2014.02.25 15:46 신고
  • 오앵무 감사합니다^^ 2014.02.25 16:32 신고
  • 오앵무 자꾸 질문 드려서 죄송해요ㅠ_ㅠ

    제가 탭으로 액티비티 여러 개를 만들고 그 중 한 액티비티에서 버튼으로 리시버를 껐다켰다 하는데요
    다른 액티비티(탭)로 이동하지 않고 버튼이 있는 액티비티에서만 껐다켰다 하면 정상적으로 작동이 돼요.
    그런데 다른 액티비티(탭)으로 이동 했다가 돌아와서 끄거나 키면 리시버 중복 실행 되거나 unregister 부분에서 에러가 납니다.
    사용하는 리시버는 딱 한 개 밖에 없어요.

    왜 이러는 걸까요ㅠㅠㅠㅠ

    +
    매니페스트에 선언하면 중지가 안 된다는 소리를 들어서 매니페스트에서는 리시버 부분 삭제했어요.
    2014.02.26 11:28 신고
  • Favicon of http://itmir.tistory.com Mir(whdghks913) 브로드캐스트리시버가 null이 아니면 unregister를 하게 해보세요
    if(myBroadCast != null)
    // 해제

    저는 리시버 해제시 강종원인이 이미 해제된 또는 등록안된 리시버를 해제하려 시도하기 때문이라고 생각해서 리시버 해제 부분을

    try-catch로 묶어 예외가 와도 강종이 안뜨도록 했습니다


    참고로 동적등록은 액티비티가 종료되면 리시버 등록이 해제되요
    그래서 이런건 서비스를 주로 이용합니다
    본문을 보면 죽지않는 서비스를 이용해 브로드캐스트를 등록한다라고 언급하고있습니다

    서비스를 시작할때 등록
    종료할때 해제

    액티비티에선 서비스 시작
    서비스 종료

    만 해주고요


    조금 자세한건 나중에 다뤄보려고요
    안드로이드 API문서를 참조해 보세요
    2014.02.26 11:48 신고
  • 오앵무 감사합니다ㅠㅠ 좋은하루 보내세요! 2014.02.26 11:58 신고
  • 윤근호 좋은정보주셔서 감사합니다 제가 지금 이작업을 하고있는데요
    메뉴를 누르면 작성되있는 메세지가 폰에 저장되있는 사람이나 번호를 누르고 문자를 발송하게하는건데요 홍보 문자죠 앱을 설치하게끔 유도하는 이걸 이용해서 해도 되는건가요??
    그리고 문자를 보내고 그걸받은사람이 설치할경우 추천인으로 보낸사람이 뜨게 하고싶은데
    이건 어떤걸 사용하면되나요???
    2015.04.24 10:10 신고
  • Favicon of http://itmir.tistory.com Mir(whdghks913) 개발하실때 뭘 이용해야 가장 최선의 방법일지 생각하는 것은 개발자의 몫입니다 그래서 뭐라 해드릴수가 없네요..

    추천인같은건.. 문자 구조에 추천인 아이디를 추가한다음 구조를 읽어오면 안될까요?

    예를들면 문자 내용이 "어서 등록해보세요! 추천인 : 미르"
    라고 한다면
    여기서 "어서 등록해보세요! 추천인 : "부분을 지우고 "미르"부분만 인식하도록 하는 방식으로..

    아니면 그냥 추천인은 사용자가 입력하게 하는 방법도 있을것 같고... 방법은 많을것 같습니다.

    여러가지 변수를 모두 고려하셔야 합니다.
    2015.04.26 13:02 신고
  • 궁금해요~ 안드로이드 4.4 이상에서 앱 설치 후 한 번은 구동 해야 SMS 반응 하는데요~

    4.3 이하에서는 잘 되구요~

    혹시 원인이나 대응 방법이 있을까요? ㅠㅠ
    2015.04.27 18:47 신고
  • Favicon of http://itmir.tistory.com Mir(whdghks913) 4.3도 그런 일이 발생한다고 들었습니다
    안드로이드 버전업이 이루어지면서 수정된 점이라고 하는데요
    해결방법은 없습니다...
    2015.04.27 18:53 신고
  • sarah 안녕하세요~안드로이드를 배운지 얼마안된 초보자입니다ㅠㅠㅠㅠ

    위강좌 따라했더니 한번에성공했어요!
    정말감사합니다
    한가지 질문이있는데
    broadcast 에있는 저 message 변수를
    Activity에 넘기고싶은데
    어떠한 방법으로전달하면 될까요?
    2015.11.24 19:42 신고
  • Favicon of http://itmir.tistory.com Mir(whdghks913) 브로드캐스트리시버에서 전달되는 Intent를 이용하여 액티비티를 띄우죠?
    intent를 이용해서 데이터를 전달해주면 됩니다.
    예를들면 intent의 putExtra에 데이터를 넣어주신다음 startActivity()하시면 됩니다.
    putExtra의 사용방법은 간단하므로 검색을 통해 확인해주시면 감사드리겠습니다...

    만약 액티비티가 실행중인 상태에서 브로드캐스트리시버를 받아서 바로 보여줘야한다면 onNewIntent에 대해서도 찾아보시면 많은 자료 얻을수 있습니다.
    2015.11.24 23:00 신고
  • 커피는아메리카노 정말 깔끔한 정리입니다. 감사합니다^^ 2016.04.20 17:37 신고
  • Favicon of http://action713.tistory.com 예쁜꽃이피었으면 감사합니다~ 2016.06.27 16:25 신고
  • 좋아좋아 안녕하세요. 강좌 잘 보고 있습니다~

    이번 강의 테스트 할 때

    앱을 실행 시킨상태에서 하는건가요??

    꺼놓고 해야 할거 같긴한데... 그럼 로그가 안남을거 같아서요??

    테스트가 잘 안되서 질문 남기네요 ㅜ
    2017.01.19 11:42 신고
  • 안드로이퐁 내용을 똑같이 복사 붙여넣기해도

    새로운 프로젝트에서는 반응을 안하네요...

    혹시 SDK 버전 때문에 그러는걸까요??
    2017.01.20 10:55 신고
  • Favicon of http://itmir.tistory.com Mir(whdghks913) Broadcast를 받으면 로그가 남습니다. 그런데 앱을 끈 상태에서 로그가 기록되면 AndroidStudio에서 (따로 설정하지 않는다면) 기록을 보기 까다로울 겁니다.
    앱을 킨 상태에서 시도해보세요.
    2017.01.20 16:46 신고
댓글쓰기 폼