1page.title=범위가 지정된 디렉터리 액세스 2page.keywords=preview, sdk, 범위가 지정된 디렉터리 액세스 3page.tags=androidn 4 5@jd:body 6 7<div id="qv-wrapper"> 8<div id="qv"> 9 <h2>이 문서의 내용</h2> 10 <ol> 11 <li><a href="#accessing">외부 저장소 디렉터리 액세스</a></li> 12 <li><a href="#removable">이동식 미디어의 디렉터리 액세스</a></li> 13 <li><a href="#best">모범 사례</a></li> 14 </ol> 15</div> 16</div> 17 18<p>일반적으로 사진 앱과 같은 앱은 19<code>Pictures</code> 디렉터리 등 외부 저장소의 특정 디렉터리에만 액세스하면 됩니다. 기존 외부 저장소 액세스 방식은 20이런 유형의 앱에 대상화된 디렉터리 액세스를 쉽게 21제공하지 못합니다. 예를 들면 다음과 같습니다.</p> 22 23<ul> 24<li>매니페스트에서 {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} 25또는 {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE}를 요청하면 26외부 저장소의 모든 공개 디렉터리에 액세스할 수 있습니다. 27이는 앱에 필요한 것보다 과도한 액세스를 제공할 수 있습니다.</li> 28<li>일반적으로, 29<a href="{@docRoot}guide/topics/providers/document-provider.html">저장소 30액세스 프레임워크</a>를 사용하면 시스템 UI를 통해 사용자가 디렉터리를 31선택할 수 있습니다. 앱이 항상 동일한 외부 디렉터리에 액세스한다면 32필요 없는 동작입니다.</li> 33</ul> 34 35<p>Android N은 일반 외부 저장소 디렉터리에 액세스하기 위한 36단순화된 새로운 API를 제공합니다. </p> 37 38<h2 id="accessing">외부 저장소 디렉터리 액세스</h2> 39 40<p><code>StorageManager</code> 클래스를 사용하여 적절한 41<code>StorageVolume</code> 인스턴스를 가져옵니다. 그 후, 해당 인스턴스의 42<code>StorageVolume.createAccessIntent()</code> 메서드를 호출하여 인텐트를 생성합니다. 43이 인텐트로 외부 저장소 디렉터리에 액세스합니다. 이동식 미디어 볼륨을 비롯한 44모든 사용 가능한 볼륨의 목록을 가져오려면 45<code>StorageManager.getVolumesList()</code>를 사용합니다.</p> 46 47<p>특정 파일에 대한 정보가 있으면 48<code>StorageManager.getStorageVolume(File)</code>을 사용하여 해당 파일이 들어 있는 49<code>StorageVolume</code>을 가져옵니다. 이 <code>StorageVolume</code>에서 50<code>createAccessIntent()</code>를 호출하여 파일의 외부 저장소 디렉터리에 51액세스합니다.</p> 52 53<p> 54외부 SD 카드와 같은 보조 볼륨에서는 특정 디렉터리 대신 전체 볼륨에 대한 액세스를 요청하려면 55<code>StorageVolume.createAccessIntent()</code>를 호출할 때 56null을 전달합니다. 기본 볼륨에 null을 전달하거나 잘못된 디렉터리 이름을 전달하는 경우 57<code>StorageVolume.createAccessIntent()</code>는 null을 58반환합니다. 59</p> 60 61<p>다음 코드 조각은 기본 공유 저장소에서 62<code>Pictures</code> 디렉터리를 여는 방법에 대한 예시입니다.</p> 63 64<pre> 65StorageManager sm = (StorageManager)getSystemService(Context.STORAGE_SERVICE); 66StorageVolume volume = sm.getPrimaryVolume(); 67Intent intent = volume.createAccessIntent(Environment.DIRECTORY_PICTURES); 68startActivityForResult(intent, request_code); 69</pre> 70 71<p>시스템이 외부 디렉터리에 액세스 권한을 부여하고자 시도하고, 72필요에 따라 단순화된 UI를 사용하는 사용자의 액세스를 확인합니다.</p> 73 74<img src="{@docRoot}preview/images/scoped-folder-access-framed.png" srcset="{@docRoot}preview/images/scoped-folder-access-framed.png 1x, 75{@docRoot}preview/images/scoped-folder-access-framed_2x.png 2x" /> 76<p class="img-caption"><strong>그림 1.</strong> Pictures 디렉터리에 77액세스를 요청하는 애플리케이션.</p> 78 79<p>사용자가 액세스 권한을 부여하면, 시스템이 80<code>Activity.RESULT_OK</code>의 결과 코드가 포함된 81<code>onActivityResult()</code> 재정의와 URI가 포함된 인텐트 데이터를 호출합니다. 제공된 82URI를 사용하여 디렉터리 정보에 액세스합니다. 83<a href="{@docRoot}guide/topics/providers/document-provider.html">저장소 84액세스 프레임워크</a>가 85반환한 URI를 사용하는 것과 유사합니다.</p> 86 87<p>사용자가 액세스 권한을 부여하지 않으면 시스템이 88<code>Activity.RESULT_CANCELED</code>의 결과 코드가 포함된 89<code>onActivityResult()</code> 재정의와 null 인텐트 데이터를 호출합니다.</p> 90 91<p class="note"><b>참고</b>: 특정 외부 디렉터리에 대한 액세스 권한을 얻으면 92해당 디렉터리의 하위 디렉터리에 대한 액세스 권한도 얻게 됩니다.</p> 93 94<h2 id="removable">이동식 미디어의 디렉터리 액세스</h2> 95 96<p>범위가 지정된 디렉터리 액세스를 사용하여 이동식 미디어의 디렉터리에 액세스하려면 97먼저 다음과 같은 98{@link android.os.Environment#MEDIA_MOUNTED} 알림을 수신하는 {@link android.content.BroadcastReceiver}를 추가합니다.</p> 99 100<pre> 101<receiver 102 android:name=".MediaMountedReceiver" 103 android:enabled="true" 104 android:exported="true" > 105 <intent-filter> 106 <action android:name="android.intent.action.MEDIA_MOUNTED" /> 107 <data android:scheme="file" /> 108 </intent-filter> 109</receiver> 110</pre> 111 112<p>사용자가 SD 카드 등의 이동식 미디어를 장착하면 시스템이 113{@link android.os.Environment#MEDIA_MOUNTED} 알림을 보냅니다. 이 알림은 114이동식 미디어 디렉터리에 액세스하는 데 사용할 수 있는 인텐트 데이터의 <code>StorageVolume</code> 객체를 115제공합니다. 다음은 116이동식 미디어의 <code>Pictures</code> 디렉터리에 액세스하는 예시입니다.</p> 117 118<pre> 119// BroadcastReceiver has already cached the MEDIA_MOUNTED 120// notification Intent in mediaMountedIntent 121StorageVolume volume = (StorageVolume) 122 mediaMountedIntent.getParcelableExtra(StorageVolume.EXTRA_STORAGE_VOLUME); 123volume.createAccessIntent(Environment.DIRECTORY_PICTURES); 124startActivityForResult(intent, request_code); 125</pre> 126 127<h2 id="best">모범 사례</h2> 128 129<p>가능하면, 사용자에게 액세스 권한을 반복적으로 요청하지 않도록 외부 디렉터리 액세스 URI를 130변경하지 마세요. 사용자가 액세스 권한을 부여하면 디렉터리 액세스 URI로 131<code>getContentResolver().takePersistableUriPermssion()</code>를 132호출합니다. 시스템이 URI를 유지하고 이후 액세스 요청에서는 133<code>RESULT_OK</code>를 반환하고 사용자에게 확인 UI를 134표시하지 않습니다.</p> 135 136<p>사용자가 외부 디렉터리 액세스를 거부하면 137다시 즉시 액세스를 요청하지 마세요. 액세스를 반복적으로 요청하면 138사용자 환경을 저해하는 결과를 낳습니다. 사용자가 요청을 거부하는데 앱이 다시 액세스를 139요청하면, UI에 <b>Don't ask again</b> 체크박스가 표시됩니다.</p> 140 141<img src="{@docRoot}preview/images/scoped-folder-access-dont-ask.png" srcset="{@docRoot}preview/images/scoped-folder-access-dont-ask.png 1x, 142{@docRoot}preview/images/scoped-folder-access-dont-ask_2x.png 2x" /> 143<p class="img-caption"><strong>그림 1.</strong> 이동식 미디어에 대해 144다시 액세스 요청을 하는 애플리케이션.</p> 145 146<p>사용자가 <b>Don't ask again</b>을 선택하여 요청을 거부하면 앱에서 해당 디렉터리에 대한 이후의 모든 147요청이 자동으로 거부되고, 148사용자에게는 어떤 요청 UI도 표시되지 않습니다.</p>