728x90

안드로이드 Broadcast 를 테스트 해보고 정리해둔다.
개념도 제대로 모른채 구글링해서 나온 예제를 실행해보고 실행이 되는구나 하는 정도만으로는 응용이 불가능하다는 걸 테스트 해보면서 몸소 느끼고 있다. Android Studio 기반에서 테스트한 것을 적어둔다.

안드로이드 6.0 에서 SMS 권한이 없는데 허용할 것인지 문의하는 창도 뜨고 잘 동작된다.


BroadCast.zip


Android Studio 는 main 폴더에 핵심적인 내용이 들어가 있으므로 이것만 파일 첨부하면 이걸 이용해서 다시 작성하기가 쉽다.


BroadcastReceiver는 모든 어플에게 다 전해지는 것이다. (시스템 매니저가 알아서 보내는 것)


// IntentFilter 전달받는 여러 인텐트중 특정 인텐트만 고르겠다는 의도
IntentFilter filter = new IntentFilter(UsbManager.ACTION_USB_DEVICE_ATTACHED);
registerReceiver(mUsbAttachReceiver , filter); // 브로드캐스트리시버 등록


또는

IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_USB_DEVICE_ATTACHED);
registerReceiver(mUsbAttachReceiver, filter);  // 브로드캐스트리시버 등록


Broadcast Receiver(방송수신자)는 BroadcastReceiver 클래스를 상속받아 작성한다.

Broadcast 메시지가 수신되면 onReceive 메서드가 자동 호출된다.

public class Broadcastreceiver extends BroadcastReceiver {

    private Bundle bundle;
    private SmsMessage currentSMS;
    private String message;

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
            Log.d("onReceive()","부팅완료");
            //Intent i = new Intent(context, ScreenService.class);
            //context.startService(i);
        }


        if (intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")) {
            Log.d("SMSBroadcastReceiver", "SMS 메시지가 수신되었습니다.");
            //Toast.makeText(context, "문자가 수신되었습니다", Toast.LENGTH_SHORT).show();
            bundle = intent.getExtras();
            if (bundle != null) {
                Object[] pdu_Objects = (Object[]) bundle.get("pdus");
                if (pdu_Objects != null) {
                    for (Object aObject : pdu_Objects) {
                        currentSMS = getIncomingMessage(aObject, bundle);
                        String senderNo = currentSMS.getDisplayOriginatingAddress();
                        message = currentSMS.getDisplayMessageBody();
                        Toast.makeText(context, "senderNum: " + senderNo + " :\n message: " + message, Toast.LENGTH_LONG).show();
                    }
                    this.abortBroadcast();
                    // End of loop
                }
            }
        } // bundle null



AndroidManifest.xml 을 사용하여 Broadcast Receiver 를 등록

- 앱이 실행중이 아니더라도 지정한 Broadcast 메시지를 수신(지정한 Action 발생)되면 Broadcast Receiver 가 자동 실행된다.


동적으로 Broadcast Receiver 를 등록하면, 앱이 실행중일 때만 Broadcast Receiver 가 수행되며, 동적으로 Broadcast Receiver 를 추가/제거가 가능하다.


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.tistory.link2me.sms_receive">

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <receiver
            android:name ="com.tistory.link2me.sms_receive.Broadcastreceiver"
            android:enabled="true">
            <intent-filter android:priority="10000">
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
                <action android:name="android.provider.Telephony.SMS_RECEIVED" />
            </intent-filter>
        </receiver>

    </application>

</manifest>


AndroidManifest.xml에 해당 리시버를 등록하고 intent-filter로 원하는 브로드캐스팅 받을 Action을 등록한다.

즉, intent-filter는 어떤 intent를 필터링해서 들을것인지 설정하는 것이다.

안드로이드 앱에서 알고 싶은 이벤트들이 있을수 있다. 가령
- 배터리 부족
- 네트워크 연결 / 중단
- SD카드 삽집 / 제거
- SMS 수신
- 카메라 버튼이 눌렸을때
- 폰의 날짜, 시간이 변동되었을때
- 비행기 모드 전환시
- 어플 설치/제거
- 재부팅/종료
- 매 분마다 수신


android:enabled="true" : 시스템이 알아서 Broadcastreceiver를 실행한다는 의미다. default 가 true 다.

android:exported="false" : 외부 어플리케이션에서는 사용할 수 없으며 같은 앱 또는 같은 UserId를 가진 놈만 호출할 수 있다는 뜻이다. (이걸 적어두면 메시지 수신이 제대로 안됨)
android:priority : 숫자가 높을수록 우선순위가 높으며, 우선순위가 높은 리시버부터 순차적으로 메세지가 전달된다.


 === Broadcastreceiver.java === 

 package com.tistory.link2me.sms_receive;

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;
import android.widget.Toast;

public class Broadcastreceiver extends BroadcastReceiver {
    private Bundle bundle;
    private SmsMessage currentSMS;
    private String message;

    @Override
    public void onReceive(Context context, Intent intent) {

        if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
            Log.d("onReceive()","부팅완료");
            //Intent i = new Intent(context, ScreenService.class);
            //context.startService(i);
        }

        if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
            Log.d("onReceive()","스크린 ON");
        }

        if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
            Log.d("onReceive()","스크린 OFF");
        }

        if (intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")) {
            Log.d("SMSBroadcastReceiver", "SMS 메시지가 수신되었습니다.");
            Toast.makeText(context, "문자가 수신되었습니다", Toast.LENGTH_SHORT).show();
            bundle = intent.getExtras();
            if (bundle != null) {
                Object[] pdu_Objects = (Object[]) bundle.get("pdus");
                if (pdu_Objects != null) {
                    for (Object aObject : pdu_Objects) {
                        currentSMS = getIncomingMessage(aObject, bundle);
                        String senderNo = currentSMS.getDisplayOriginatingAddress();
                        message = currentSMS.getDisplayMessageBody();
                        Toast.makeText(context, "senderNum: " + senderNo + " :\n message: " + message, Toast.LENGTH_LONG).show();
                    }
                    this.abortBroadcast();
                    // End of loop
                }
            }
        } // bundle null
    }

    private SmsMessage getIncomingMessage(Object aObject, Bundle bundle) {
        SmsMessage currentSMS;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            String format = bundle.getString("format");
            currentSMS = SmsMessage.createFromPdu((byte[]) aObject, format);
        } else {
            currentSMS = SmsMessage.createFromPdu((byte[]) aObject);
        }
        return currentSMS;
    }
}


문자수신시각 정보 추가시

Date curDate = new Date(currentSMS.getTimestampMillis());
SimpleDateFormat sdf = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" );
String receivedDate = sdf.format( curDate );



=== MainActivity.java ===

 package com.tistory.link2me.sms_receive;

import android.Manifest;
import android.content.pm.PackageManager;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        int permissionCheck = ContextCompat.checkSelfPermission(this, Manifest.permission.RECEIVE_SMS);
        if(permissionCheck == PackageManager.PERMISSION_GRANTED){
            Toast.makeText(this, "SMS 수신권한 있음", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(this, "SMS 수신권한 없음", Toast.LENGTH_SHORT).show();
            if(ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.RECEIVE_SMS)){
                Toast.makeText(this, "SMS 권한 설정이 필요함", Toast.LENGTH_SHORT).show();
            } else {
                // 권한이 할당되지 않았으면 해당 권한을 요청
                ActivityCompat.requestPermissions(this,new String[] {Manifest.permission.RECEIVE_SMS},1);
            }
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        if (requestCode == 1) {
            for (int i = 0; i < permissions.length; i++) {
                if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
                    Toast.makeText(this, permissions[i] + " 권한이 승인됨.", Toast.LENGTH_LONG).show();
                } else {
                    Toast.makeText(this, permissions[i] + " 권한이 거부됨.", Toast.LENGTH_LONG).show();
                }
            }
        }
    }

}



블로그 이미지

Link2Me

,