지식메모/안드로이드 Android

안드로이드 마쉬멜로우 6.0 권한 허용 팝업 기능 추가하기

yonoo 2016. 8. 2. 14:42
반응형





https://blog.stylingandroid.com/permissions-part-3/

위 블로그 글을 참고 하였고 

프로젝트는 작성자의 깃허브 사이트 

https://github.com/StylingAndroid/Permissions/tree/Part3

를 참고 하였다.


프로젝트를 실행하면 이러한 모습이다



코드를 참고하면서 내 프로젝트에 필요한 것만 참고함.


먼저

PermissionsActivity.java 와 PermissionsChecker.java를 프로젝트에 붙여넣기 하였다.

추가 설명은 코드 내 주석을 달아놓았다.



PermissionsActivity.java

37라인

setContentView(R.layout.new_custom_full);

이 부분은 팝업을 표시할 액티비티의 xml 파일명으로 변경해준다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
 
 
import android.app.Activity;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
 
public class PermissionsActivity extends AppCompatActivity {
    public static final int PERMISSIONS_GRANTED = 0;
    public static final int PERMISSIONS_DENIED = 1;
 
    private static final int PERMISSION_REQUEST_CODE = 0;
    private static final String EXTRA_PERMISSIONS = "com.stylingandroid.permissions.EXTRA_PERMISSIONS";
    private static final String PACKAGE_URL_SCHEME = "package:";
 
    private PermissionsChecker checker;
    private boolean requiresCheck;
 
    public static void startActivityForResult(Activity activity, int requestCode, String... permissions) {
        Intent intent = new Intent(activity, PermissionsActivity.class);
        intent.putExtra(EXTRA_PERMISSIONS, permissions);
        ActivityCompat.startActivityForResult(activity, intent, requestCode, null);
    }
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getIntent() == null || !getIntent().hasExtra(EXTRA_PERMISSIONS)) {
            throw new RuntimeException("This Activity needs to be launched using the static startActivityForResult() method.");
        }
        setContentView(R.layout.new_custom_full); //xml 파일명 변경 필요
 
        checker = new PermissionsChecker(this);
        requiresCheck = true;
    }
 
    @Override
    protected void onResume() {
        super.onResume();
        if (requiresCheck) {
            String[] permissions = getPermissions();
 
            if (checker.lacksPermissions(permissions)) {
                requestPermissions(permissions);
            } else {
                allPermissionsGranted();
            }
        } else {
            requiresCheck = true;
        }
    }
 
    private String[] getPermissions() {
        return getIntent().getStringArrayExtra(EXTRA_PERMISSIONS);
    }
 
    private void requestPermissions(String... permissions) {
        ActivityCompat.requestPermissions(this, permissions, PERMISSION_REQUEST_CODE);
    }
 
    private void allPermissionsGranted() {
        setResult(PERMISSIONS_GRANTED);
        finish();
    }
 
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (requestCode == PERMISSION_REQUEST_CODE && hasAllPermissionsGranted(grantResults)) {
            requiresCheck = true;
            allPermissionsGranted();
        } else {
            requiresCheck = false;
            showMissingPermissionDialog();
        }
    }
 
    private boolean hasAllPermissionsGranted(@NonNull int[] grantResults) {
        for (int grantResult : grantResults) {
            if (grantResult == PackageManager.PERMISSION_DENIED) {
                return false;
            }
        }
        return true;
    }
 
    //모두 거부 하였을 때 나타나는 팝업 창 설정입니다.
    private void showMissingPermissionDialog() {
        AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(PermissionsActivity.this);
        dialogBuilder.setTitle(R.string.help); //팝업 창 타이틀
        //팝업 안내 메시지 부분으로 string.xml에서 설정한 메시지를 노출합니다.
        dialogBuilder.setMessage(R.string.string_help_text);
        //팝업 창 버튼 2개를 노출합니다.
        //확인버튼을 누르면 앱 종료?인데 저는 팝업 창만 사라졌네요
        dialogBuilder.setNegativeButton(R.string.quit, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                setResult(PERMISSIONS_DENIED);
                finish();
            }
        });
        //설정 버튼을 누르면 설정 화면으로 이동합니다.
       dialogBuilder.setPositiveButton(R.string.settings, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                startAppSettings();
            }
        });
        dialogBuilder.show();
    }
 
     private void startAppSettings() {
        Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        intent.setData(Uri.parse(PACKAGE_URL_SCHEME + getPackageName()));
        startActivity(intent);
    }
}
cs



PermissionsChecker.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import android.content.Context;
import android.content.pm.PackageManager;
import android.support.v4.content.ContextCompat;
 
class PermissionsChecker {
    private final Context context;
 
    public PermissionsChecker(Context context) {
        this.context = context;
    }
 
    public boolean lacksPermissions(String... permissions) {
        for (String permission : permissions) {
            if (lacksPermission(permission)) {
                return true;
            }
        }
        return false;
    }
 
    private boolean lacksPermission(String permission) {
        return ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_DENIED;
    }
 
}
 
cs


발생하는 에러는 알맞게 처리한 다음

AndroidMenifest.xml 에 PermissionsActivity를 추가해준다.

1
2
3
4
5
6
7
8
9
10
        <!--PermissionsActivity 를 추가해줍니다.-->
        <!--팝업 적용을 위해 @style:AppTheme 추가해줍니다-->
        <activity
            android:name="com.yonoo.my.PermissionsActivity"
            android:configChanges="orientation|screenSize|screenLayout|keyboard|keyboardHidden"
            android:label="@string/app_name"
            android:theme="@style/AppTheme"
            android:screenOrientation="nosensor" >
        </activity>
 
cs


권한도 추가

1
2
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  <uses-permission android:name="android.permission.CAMERA" />
cs



앱 테마 적용을 위해 style.xml에 다음을 추가해준다.

(다국어 설정이 되어있다면 국가별 style.xml에도 추가해준다.)

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"</style>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<resources>
 
    <!--
        Base application theme, dependent on API level. This theme is replaced
        by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
    -->
    <style name="AppBaseTheme" parent="android:Theme.Light">
        <!--
            Theme customizations available in newer API levels can go in
            res/values-vXX/styles.xml, while customizations related to
            backward-compatibility can go here.
        -->
    </style>
    <!--팝업 호출을 위해 아래 스타일이 필요합니다.-->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    </style>
</resources>
 
cs


그리고 권한 팝업 노출시 권한 설명을 위한 메시지를 string.xml에 추가하여준다. 마찬가지로 다국어 string에도 추가

이 메시지는 PermissonsActivity의 showMissingPermissionDialog에서 사용된다.

1
2
3
4
5
6
    <!--권한 팝업에서 노출될 메시지를 설정합니다.-->
    <string name="settings">설정</string>
    <string name="help">Help</string>
    <string name="string_help_text"> 저장소와 카메라 권한이 필요합니다. </string>
    <string name="quit">확인</string>
 
cs


그리고 권한 팝업을 띄울 액티비티파일에 다음 코드를 추가해준다.

ex) NewCustomFullActivity 에 권한 팝업을 띄울거라면 변수를 추가

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class NewCustomFullActivity implements OnClickListener{
 
    //권한 체크를 위한 값 선언
    private static final int REQUEST_CODE = 0;
    /*요청받은 권한을 설정합니다. 여기선 저장소와 카메라를 설정
    * android.Manifest.permission.WRITE_EXTERNAL_STORAGE
    * android.Manifest.permission.CAMERA
    * */
    private static final String[] PERMISSIONS = 
            new String[]{
                    android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
                    android.Manifest.permission.CAMERA
            };
    //PermissionChecker를 사용하기 위해 선언
    private PermissionsChecker checker;
cs


OnCreate에 다음 코드 추가

1
2
//Oncreate 에서 Checker를 호출
checker = new PermissionsChecker(this);
cs


그리고 다음 함수를 추가해준다.

1
2
3
    private void startPermissionsActivity() {
        PermissionsActivity.startActivityForResult(this, REQUEST_CODE, PERMISSIONS);
    }
cs


이제 팝업을 어디서 띄울지 결정해야했는데 카메라를 선택했을 때 띄우기로 결정

그래서 startActivityForResult(intent, PICK_FROM_CAMERA); 이 부분이 호출될 때 팝업이 뜨게 하였다.

권한 때문에 SecurtiyException 이 발생할 때

1
2
3
4
    //권한을 체크
    if (checker.lacksPermissions(PERMISSIONS)) {
        startPermissionsActivity();
    }
cs

이 부분을 추가해주어 권한 허용 유무를 체크하여 미허용상태면 팝업을 띄우도록 startPermissionsActivity() 을 요청한다.


추가된 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//카메라를 호출할 때 권한이 없으면 권한요청팝업이 뜨도록 설정
try{
    startActivityForResult(intent, PICK_FROM_CAMERA);
}catch (SecurityException e) {
    //권한을 체크
    if (checker.lacksPermissions(PERMISSIONS)) {
        startPermissionsActivity();
    }
    //토스트로 안내메시지도 같이 호출해보았습니다.
    e.printStackTrace();
    if(language.equals("en"|| language.equals("th"|| language.equals("vi"))
        Toast.makeText(getApplicationContext(),
                "check phone settinig >  application manager > app permission Camera approve",
                Toast.LENGTH_LONG).show();
    else
        Toast.makeText(getApplicationContext(),
                "설정 > 애플리케이션 관리자 >앱권한에서 카메라 권한을 허용해주세요",
                Toast.LENGTH_LONG).show();
}
cs


이렇게 해주면 카메라를 킬 때 허용 팝업이 노출된다.


외국인 블로거가 짜놓은 코드를 사용하였기 때문에 자세한 설명보다는 크게 크게 이해해보려고 하였다.

나중을 위해서 적어 놓은건데 빼 먹은 건 없나 모르겠다.


원래는 앱 시작하자마자 팝업 띄우려고 헀는데 뭔가 계속 안된다.. 

그래서 그냥 해당기능 켤 때  띄우는 걸로..


이런 걸 취미로 포스팅 하는 개발자들은 참 대단하다.

난 아무리 봐도 이해가 안가는데..





반응형