안드로이드 6.0 (Marshmallow) 권한 획득하기!
개발/안드로이드 2017. 8. 4. 20:44
안드로이드 6.0 (Marshmallow)에서 권한 획득 하는 방법에 대해서 소개하려 합니다.
안드로이드 6.0 은 API Level이 23 이므로 이후 표기 버전은 API 23 이라고 하도록 하겠습니다.
권한 획득이란?
API 22 이하에서는 "AndroidManifest.xml"에 permission을 지정할 수 있었으나 API 23이상에서는 Runtime Permission으로 변경되었습니다.
Permission 이 필요한 시점에 권한을 요청/수락하여 Permission 을 획득하는 방식입니다.
<권한 획득 할때 나오는 팝업>
기본적으로 Permission 종류는 API 23 이전과 거의 동일합니다.
아래는 구글에서 제공하는 권한 및 권한 그룹 표입니다.
권한 그룹 |
권한 |
CALENDAR |
READ_CALENDAR WRITE_CALENDAR |
CAMERA |
CAMERA |
CONTACTS |
READ_CONTACTS WRITE_CONTACTS GET_ACCOUNTS |
LOCATION |
ACCESS_FINE_LOCATION ACCESS_COARSE_LOCATION |
MICROPHONE |
RECORD_AUDIO |
PHONE |
READ_PHONE_STATE CALL_PHONE READ_CALL_LOG WRITE_CALL_LOG ADD_VOICEMAIL USE_SIP PROCESS_OUTGOING_CALLS |
SENSORS |
BODY_SENSORS |
SMS |
SEND_SMS RECEIVE_SMS READ_SMS RECEIVE_WAP_PUSH RECEIVE_MMS |
STORAGE |
READ_EXTERNAL_STORAGE WRITE_EXTERNAL_STORAGE |
<구글에서 제공하는 권한 및 권한 그룹 표>
(https://developer.android.com/guide/topics/security/permissions.html?hl=ko#normal-dangerous)
API 23에서는 권한 그룹이라는게 있습니다.
그룹으로 권한을 획득하게 되면 해당 그룹에 속해있는 권한을 모두 받을 수 있습니다.
권한 획득 주요 API
권한 획득에 필요한 주요 API는 아래 표와 같습니다.
API |
설명 |
checkSelfPermission |
권한 획득 상태 체크 |
shouldShowRequestPermissionRationale |
권한 재요청 여부 확인 |
requestPermissions |
권한 요청 |
onRequestPermissionsResult |
권한 획득 정보 Callback |
권한 API는 코드를 보는게 이해가 빠르므로 간단하게 작성하였습니다.
"아~ 이런게 있구나"라고 생각하시면 되겠습니다.
Read/Write External Storage 권한이 필요한 예제 코드
권한이 필요한 예제코드를 살펴보고 해당권한을 어떻게 얻는지 추후에 살펴 보도록 하겠습니다.
public void startApp()
{
File file = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
String strDir = file.getAbsolutePath();
File oFile = new File(strDir+"/abc.txt");
FileOutputStream oFos;
try
{
oFos = new FileOutputStream(oFile);
oFos.write("abc".getBytes(), 0, 3);
oFos.close();
} catch (IOException e)
{
e.printStackTrace();
}
}
위 코드는 다운로드 폴더에 "abc.txt" 파일을 만들고 "abc" 라는 텍스트를 입력하는 예제 코드입니다.
코드 실행 시 Android Monitor에 아래와 같이 Permission denied Exception을 발생시킵니다.
java.io.FileNotFoundException: /storage/emulated/0/Download/abc.txt (Permission denied)
at java.io.FileOutputStream.open(Native Method)
at java.io.FileOutputStream.<init>(FileOutputStream.java:221)
at java.io.FileOutputStream.<init>(FileOutputStream.java:169)
at twomix.co.kr.runtimepermission.MainActivity.onCreate(MainActivity.java:45)
at android.app.Activity.performCreate(Activity.java:6955)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1126)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2927)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3045)
at android.app.ActivityThread.-wrap14(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1642)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6776)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1520)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1410)
권한 API 예제 코드
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
m_oMainActivity = this;
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
{
checkVerify();
}
else
{
startApp();
}
}
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { checkVerify(); } else { startApp(); } |
API 23이상이면 checkVerify() 메소드를 실행하고 API 22 이하이면 startApp() 메소드를 실행합니다. 실제 앱을 실행하는 코드는 startApp() 에 있습니다. |
public void startApp()
{
File file = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
String strDir = file.getAbsolutePath();
File oFile = new File(strDir+"/abc.txt");
FileOutputStream oFos;
try
{
oFos = new FileOutputStream(oFile);
oFos.write("abc".getBytes(), 0, 3);
oFos.close();
} catch (IOException e)
{
e.printStackTrace();
}
}
@TargetApi(Build.VERSION_CODES.M)
public void checkVerify()
{
if (
checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED ||
checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
)
{
// Should we show an explanation?
if (shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE))
{
// ...
}
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE},
1);
}
else
{
startApp();
}
}
if ( checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED ) |
checkSelfPermission 메소드는 인자에 해당하는 권한 여부를 리턴합니다. 현재 코드는 저장소에 Read/Write 권한이 있는지 확인 하는 코드입니다. |
if (shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)) |
권한 팝업에서 한번이라도 거부한 경우에 shouldShowRequestPermissionRationale 메소드가 true 를 리턴하게 됩니다. 그리고 권한 팝업 요청 시 "다시 묻지 않음" 체크버튼이 나타나게 됩니다.
|
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}, 1); |
권한 팝업을 요청하는 메소드 입니다. 여러개 권한을 요청해야 할 경우 String[] 로 담아 요청 하시면 됩니다. 위 코드에서는 WRITE_EXTERNAL_STORAGE, READ_EXTERNAL_STORAGE 두개의 권한을 요청하고 있습니다. |
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
{
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 1)
{
if (grantResults.length > 0)
{
for (int i=0; i<grantResults.length; ++i)
{
if (grantResults[i] == PackageManager.PERMISSION_DENIED)
{
// 하나라도 거부한다면.
new AlertDialog.Builder(this).setTitle("알림").setMessage("권한을 허용해주셔야 앱을 이용할 수 있습니다.")
.setPositiveButton("종료", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
m_oMainActivity.finish();
}
}).setNegativeButton("권한 설정", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
.setData(Uri.parse("package:" + getApplicationContext().getPackageName()));
getApplicationContext().startActivity(intent);
}
}).setCancelable(false).show();
return;
}
}
startApp();
}
}
}
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) |
||||||
onRequestPermissionsResult 메소드는 권한요청 팝업 Callback 메소드 입니다. 모든 요청 권한에 대한 획득 여부를 확인 후 한개라도 권환 획득 실패 시 팝업을 띄워주고 있는 코드 입니다. 아래는 onRequestPermissionsResult 메소드 인자 설명입니다.
|
마무리
Target Sdk Version이 API 23 이상이면 필히 구현해야할 코드입니다. 한번 잘 구현해 놓으면 가져다 쓸 수 있으니 잘 이해하셔야 합니다.
전체 소스도 참고하시면 많은 도움이 되실 껍니다.
좋은 앱 만드세요~!!!
전체 소스 다운로드
'개발 > 안드로이드' 카테고리의 다른 글
안드로이드,아이폰에서 euc-kr 한글을 utf-8 변환 (euc-kr -> utf-8) (0) | 2017.09.07 |
---|---|
Dialog 팝업창 종류 및 커스텀 Dialog 팝업창 (0) | 2017.09.05 |
앱내 Webview에서 HTTPS 처리 이슈 (0) | 2017.08.09 |
안드로이드 String 메모리 보안이슈 해결하기 (메모리 취약점) #1 (0) | 2017.08.06 |
모바일웹 - 앱내 webview를 이용하여 확대/축소 하기 (0) | 2017.08.02 |
HTTP download (http 파일 다운로드 하기) (0) | 2017.07.27 |
안드로이드 확장자별 파일 열기 (0) | 2017.07.26 |
AlertDialog 에서 Back 버튼 막아버리기!! (0) | 2017.07.18 |