나만의 개발노트

[안드로이드] 권한, 위험권한, permission, RECEIVE_SMS 본문

[안드로이드]/[안드로이드] 공부 기록

[안드로이드] 권한, 위험권한, permission, RECEIVE_SMS

노트포미 2023. 11. 16. 16:45

하라는대로 다 했는데 왜 나만 안될까....


 

권한 (Permission)

 *Android 6.0(API 23/마쉬멜로 버전) 이상에서 일반권한과 위험권한이 나뉨

 

- 설치 시간 권한

   : 최소한 필요한 권한 

     앱 세부정보에 안내가 되어 있고, 사용자가 앱을 설치할 때 자동으로 앱에 권한을 부여함

- 런타임 권한 (위험 권한)

   : 마이크, 카메라 등 민감한 정보 사용할 때 

     앱을 실행하는 시점에, 권한을 요청

   * 권한 요청 메시지는 '시스템'이 띄

 

 

(일반권한, 서명권한, 특별권한도 있음)

https://developer.android.com/guide/topics/permissions/overview?hl=ko

 

[위험 권한 종류]

출처:  https://ieeexplore.ieee.org/document/9272963

 


[위험권한 사용법]

출처: https://developer.android.com/training/permissions/requesting?hl=ko

 

1. Manifest.xml에 권한 선언

uses-permission 태그 사용

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

 

*일부 하드웨어 및 소프트웨어 기능 상수는 <uses-feature> 시스템을 사용하여

    API가 필요하다고 선언하기 전에 API를 사용할 수도 있음

   (참고 : https://developer.android.com/guide/topics/manifest/uses-feature-element?hl=ko#permissions-features )

               https://developer.android.com/guide/topics/manifest/uses-feature-element?hl=ko

<uses-feature
    android:name="android.hardware.telephony"
    android:required="false" />

2. 권한을 사용할 UI 구성

- SMS를 표시할 SmsActivity.java, activity_sms.xml 작성

https://itnote-for-me.tistory.com/46

 

[안드로이드] 브로드캐스트 수신자, onReceiver, SMS메시지 수신 어플

메모 : ***22버전 이후 위험권한으로 SMS 수신 안되는 부분 수정 필요***(아래 코드는 22 이전 버전에서만 작동합니다)브로드캐스트 수신자 (Broadcast Receiver): 앱에서 브로드캐스팅 메시지를 받고 싶

itnote-for-me.tistory.com


 

3. 앱에 이미 권한이 부여되었는지 확인 (권한이 필요할 때마다)

+ 권한이 없는 경우, 권한을 요청하는 이유 안내

int permissionCheck = ContextCompat.checkSelfPermission(this,Manifest.permission.RECEIVE_SMS);

(참고 : https://developer.android.com/reference/androidx/core/content/ContextCompat#checkSelfPermission(android.content.Context,%20java.lang.String) )

 

- shouldShowRequestPermissionRationale() 을 사용하여, 사용자가 권한 설명을 원하는지 확인

- requestPermission() 을 사용하여 시스템이 권한 요청 코드를 관리하도록 허용

   1) 시스템이 권한 요청 코드를 관리하도록 허용

*CONTEXT, REQUESTED_PERMISSION는 상황에 맞게 적절히 변경

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        if (ContextCompat.checkSelfPermission(
        CONTEXT, Manifest.permission.REQUESTED_PERMISSION) ==
        PackageManager.PERMISSION_GRANTED) {
            // You can use the API that requires the permission.
            performAction(...);
        } else if (shouldShowRequestPermissionRationale(...)) {
            // In an educational UI, explain to the user why your app requires this
            // permission for a specific feature to behave as expected, and what
            // features are disabled if it's declined. In this UI, include a
            // "cancel" or "no thanks" button that lets the user continue
            // using your app without granting the permission.
            showInContextUI(...);
        } else {
            // You can directly ask for the permission.
            // The registered ActivityResultCallback gets the result of this request.
            requestPermissionLauncher.launch(
                    Manifest.permission.REQUESTED_PERMISSION);
        }
    }

	

private ActivityResultLauncher<String> requestPermissionLauncher =
    registerForActivityResult(new RequestPermission(), isGranted -> {
        if (isGranted) {
          //권한이 허용됨. 계속 진행
        } else {
           //사용자에게 권한 거부로 인해 사용 못하는 기능 안내
        }
    });

 

 2) 권한 요청 코드 직접 관리

*CONTEXT, REQUESTED_PERMISSION,REQUEST_CODE 는 상황에 맞게 적절히 변경

//MainActivity.java 의 onCreate() 내부에
if (ContextCompat.checkSelfPermission(
        CONTEXT, Manifest.permission.REQUESTED_PERMISSION) ==
        PackageManager.PERMISSION_GRANTED) {
    performAction(...);
} else if (shouldShowRequestPermissionRationale(...)) {
    showInContextUI(...);
} else {
    requestPermissions('CONTEXT',
            new String[] { Manifest.permission.REQUESTED_PERMISSION },
            REQUEST_CODE);
}

//사용자가 시스템 권한 대화상자에 응답하면, 시스템은 앱의 onRequestPermissionResult()을 호출함
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions,
        int[] grantResults) {
    switch (requestCode) {
        case PERMISSION_REQUEST_CODE:
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0 &&
                    grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // Permission is granted. Continue the action or workflow
                // in your app.
            }  else {
                // Explain to the user that the feature is unavailable because
                // the feature requires a permission that the user has denied.
                // At the same time, respect the user's decision. Don't link to
                // system settings in an effort to convince the user to change
                // their decision.
            }
            return;
        }
        // Other 'case' lines to check for other
        // permissions this app might request.
    }
}

 

3. 런타임 권한 요청 메시지 표시

4. 런타임 권한 부여에 대한 응답 확인


#최종 Manifest.xml

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

    <uses-feature
        android:name="android.hardware.telephony"
        android:required="false" />
    <uses-permission android:name="android.permission.RECEIVE_SMS"/>

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.MySMSReceiver"
        tools:targetApi="31">
        <activity
            android:name=".SmsActivity"
            android:exported="false" />

        <receiver
            android:name=".SmsReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter android:priority="10000">
                <action android:name="android.provier.Telephony.SMS_RECEIVED" />
            </intent-filter>
        </receiver>

        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

 

#최종 MainActivity.java

package com.example.mysmsreceiver;

import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;

import android.content.BroadcastReceiver;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.os.Bundle;
import android.Manifest;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

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

//        BroadcastReceiver br = new SmsReceiver();
//        IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
//        filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
//        this.registerReceiver(br,filter);


        int permissionCheck = ContextCompat.checkSelfPermission(this,Manifest.permission.RECEIVE_SMS);
        //권한이 이미 있는 경우
        if(permissionCheck == PackageManager.PERMISSION_GRANTED){
            Toast.makeText(this,"SMS 수신 권한 있음",Toast.LENGTH_LONG).show();
        }
        //권한이 없는 경우
        else{
            Toast.makeText(this,"SMS 수신 권한 없음",Toast.LENGTH_LONG).show();
            //RECEIVE_SMS에 관한 권한에 대해서 인지
            if(shouldShowRequestPermissionRationale(Manifest.permission.RECEIVE_SMS)){
                Toast.makeText(this,"SMS 권한 설명 필요함", Toast.LENGTH_LONG).show();
            }else{
                //사용자에게 교육용 UI가 표시되거나 shouldShowRequestPermissionRationale()의 반환값에서 설명을 표시하지 않아도 된다고 나타나면
                //권한 요청하는 대화상자 표시 **시스템에서 하는 것
                requestPermissions(new String[]{Manifest.permission.RECEIVE_SMS},1);
            }
        }
    }

    //사용자가 권한 대화상자에 응답하면 시스템은 앱의 onRequestPermissionsResult()를 호출
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            //requestCode가 1인 RECEIVE_SMS에 대한 권한인 경우
            case 1:
                //request가 취소되면, grantResults가 비어있음
                //request 응답받았다면
                if(grantResults.length>0){
                    if(grantResults[0] == PERMISSION_GRANTED){
                        Toast.makeText(this,"SMS 수신 권한을 사용자가 승인함",Toast.LENGTH_LONG).show();
                    }else if(grantResults[0] == PERMISSION_DENIED){
                        Toast.makeText(this,"SMS 수신 권한을 사용자가 거부함",Toast.LENGTH_LONG).show();
                        //권한이 거부된 경우, 거부에 따른 영향을 설명해야함
                        //Android 11(API수준 30)부터 특정 권한에 관해 2번 이상 거부하면, 그 권한을 다시 묻지 않음
                    }
                }else{
                    //request 응답 받지 못한 경우
                    Toast.makeText(this,"SMS 수신 권한을 부여받지 못함",Toast.LENGTH_LONG).show();
                }
        }
    }
}

 


[참조]

https://www.boostcourse.org/mo316/lecture/22591?isDesc=false

 

안드로이드 앱 프로그래밍

부스트코스 무료 강의

www.boostcourse.org

https://developer.android.com/guide/topics/permissions/overview?hl=ko

 

Android에서의 권한  |  Android 개발자  |  Android Developers

Android에서의 권한 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 앱 권한은 다음 항목에 대한 액세스를 보호하여 사용자 개인 정보 보호를 지원합니다. 제

developer.android.com

https://developer.android.com/training/permissions/requesting?hl=ko

 

런타임 권한 요청  |  Android 개발자  |  Android Developers

런타임 권한 요청 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 모든 Android 앱은 액세스가 제한된 샌드박스에서 실행됩니다. 앱이 자체 샌드박스 밖에 있

developer.android.com

https://google-developer-training.github.io/android-developer-phone-sms-course/Lesson%202/2_p_2_sending_sms_messages.html

 

2.2: Sending and Receiving SMS Messages - Part 2 · GitBook

2.2: Part 2 - Sending and Receiving SMS Messages Contents: Task 3. Receive SMS messages with a broadcast receiver To receive SMS messages, use the onReceive() method of the BroadcastReceiver class. The Android framework sends out system broadcasts of event

google-developer-training.github.io