1page.title=权限
2page.tags=previewresources, androidm
3page.keywords=permissions, runtime, preview
4page.image={@docRoot}preview/features/images/permissions_check.png
5@jd:body
6
7
8<div id="qv-wrapper">
9  <div id="qv">
10    <h2>内容快览</h2>
11    <ul>
12      <li>如果您的应用主要面向 M 预览版 SDK,则会在运行时(而非安装时)提示用户授予权限。
13</li>
14      <li>用户可以随时从应用“设置”屏幕撤销权限。
15</li>
16      <li>每次运行时,应用均需检查自身是否具备所需的权限。
17</li>
18    </ul>
19
20    <h2>本文内容</h2>
21    <ol>
22      <li><a href="#overview">概览</a></li>
23      <li><a href="#coding">为运行时权限编码</a></li>
24      <li><a href="#testing">测试运行时权限</a></li>
25      <li><a href="#best-practices">最佳做法</a></li>
26    </ol>
27
28<!--
29  <h2>Related Samples</h2>
30  <ol>
31    <li></li>
32  </ol>
33-->
34
35<!--
36  <h2>See also</h2>
37  <ol>
38    <li></li>
39  </ol>
40-->
41  </div> <!-- qv -->
42</div> <!-- qv-wrapper -->
43
44
45<p>
46  M 开发者预览版引入了一种新的应用权限模型,旨在简化用户安装和升级应用的过程。
47如果在 M 预览版上运行的应用支持新权限模型,则用户无需在安装或升级应用时授予任何权限。相反,应用会根据需要请求权限,且系统将向用户显示一个请求权限的对话框。
48
49
50
51
52</p>
53
54<p>
55  如果应用支持新权限模型,则仍可在运行旧版 Android 的设备上使用旧权限模型安装并运行此应用。
56
57
58</p>
59
60<h2 id="overview">
61  概览
62</h2>
63
64<p>
65  通过 M 开发者预览版,该平台引入了新的应用权限模型。
66以下概述了此新模型的主要组件:
67</p>
68
69<ul>
70  <li>
71    <strong>声明权限:</strong>应用使用清单文件声明其所需的所有权限,就像在早期的 Android 平台中一样。
72
73  </li>
74
75  <li>
76    <strong>权限组:</strong>权限根据相应的功能分为若干
77<em>权限组</em>。例如,
78<code>CONTACTS</code> 权限组包含读取和写入用户联系人和个人资料信息的权限。
79
80  </li>
81
82  <li>
83    <p><strong>安装时授予的有限权限:</strong>当用户安装或更新应用时,系统将授予应用所请求的属于 {@link
84    android.content.pm.PermissionInfo#PROTECTION_NORMAL PROTECTION_NORMAL} 的所有权限。
85
86
87    例如,闹铃和 Internet 权限属于 {@link
88    android.content.pm.PermissionInfo#PROTECTION_NORMAL PROTECTION_NORMAL},因此系统将在安装应用时自动授予这些权限。
89
90    </p>
91
92    <p>此外,系统还可以授予应用签名和系统权限,如<a href="#system-apps">系统应用和签名权限</a>中所述。
93
94系统不会在安装应用时提示用户授予任何权限。<em></em>
95</p>
96  </li>
97
98  <li>
99    <strong>用户在运行时授予权限:</strong>当应用请求权限时,系统将向用户显示一个对话框,然后调用应用的回调函数来通知它是否已授予权限。
100
101如果用户授予某项权限,则应用将获得应用清单文件中声明的、该权限功能区域中的所有权限。
102
103
104  </li>
105
106</ul>
107
108<p>
109  对于需要权限的功能,此权限模型将改变应用的行为方式。
110以下概述了您调整此模型时所应遵循的开发实践:
111
112</p>
113
114<ul>
115
116  <li>
117    <strong>始终检查权限:</strong>当应用必须执行任何需要权限的操作时,应先检查它是否已具备该权限。
118
119如果没有,则请求授予该权限。
120
121  </li>
122
123  <li>
124    <strong>妥善处理权限不足的情况:</strong>如果应用未被授予适当的权限,则应正常处理失败情况。
125
126    例如,如果只有新增的功能需要该权限,则应用可以禁用该功能。
127如果该权限对于应用正常运行至关重要,则应用可能会禁用其所有功能,并通知用户需要授予该权限。
128
129
130  </li>
131
132  <div class="figure" style="width:220px" id="fig-perms-screen">
133    <img src="{@docRoot}preview/features/images/app-permissions-screen_2x.png" srcset="{@docRoot}preview/features/images/app-permissions-screen.png 1x, {@docRoot}preview/features/images/app-permissions-screen_2x.png 2x" alt="" width="220">
134    <p class="img-caption">
135      <strong>图 1.</strong>应用“设置”中的“权限”屏幕。
136    </p>
137  </div>
138
139  <li>
140    <strong>权限可撤销:</strong>用户可以随时撤销应用的权限。
141即使用户禁用应用的权限,应用也不会收到通知。<em></em>
142再次强调:您的应用应在执行任何受限操作之前验证是否具备所需的权限。
143
144  </li>
145</ul>
146
147<p class="note">
148  <strong>注:</strong>如果应用主要面向 M 开发者预览版,则必须使用新权限模型。
149<em></em>
150</p>
151
152<p>
153  截至 M 开发者预览版发布,并非所有 Google 应用均已完全实现新权限模型。
154Google 会在 M 开发者预览版运行期间更新这些应用,以便严格遵守权限切换设置。
155
156
157</p>
158
159<p class="note">
160  <strong>注:</strong>如果您的应用拥有自己的 API 接口,请先确保调用方具备访问该数据所需的必要权限,然后再代理权限。
161
162
163</p>
164
165<h3 id="system-apps">
166  系统应用和签名权限
167</h3>
168
169<p>
170  通常,当用户安装应用时,系统仅授予应用
171 {@link android.content.pm.PermissionInfo#PROTECTION_NORMAL
172  PROTECTION_NORMAL}。但在某些情况下,系统将授予应用更多权限:
173
174</p>
175
176<ul>
177  <li>如果应用是系统映像的一部分,则系统会自动授予该应用清单文件中列出的所有权限。
178
179  </li>
180
181  <li>如果应用请求提供清单文件中属于 {@link
182  android.content.pm.PermissionInfo#PROTECTION_SIGNATURE PROTECTION_SIGNATURE} 的权限,且该应用已使用与声明这些权限的应用相同的证书进行签名,则系统将在安装请求权限的应用时向其授予这些权限。
183
184
185
186  </li>
187</ul>
188
189<p>
190  在这两种情况下,用户仍可随时撤销权限,具体方法是:转到系统的<strong>设置</strong>屏幕,然后选择<strong>应用 &gt;</strong>
191
192 <i>应用名称</i> <strong>&gt; 权限</strong>。应用应在运行时继续检查权限,并根据需要请求权限。
193
194
195</p>
196
197<h3 id="compatibility">
198  前后兼容性
199</h3>
200
201<p>
202  如果应用并非面向 M 开发者预览版,则即使是在 M 预览版设备上,该应用也会继续使用旧权限模型。
203当用户安装应用时,系统将要求用户授予应用清单文件中列出的所有权限。
204
205
206</p>
207
208<p class="note">
209  <strong>注:</strong>在运行 M 开发者预览版的设备上,用户可以从应用的“设置”屏幕禁用任何应用(包括旧版应用)的权限。
210
211如果用户禁用某旧版应用的权限,则系统将以静默方式禁用相应的功能。
212当应用尝试执行需要该权限的操作时,该操作不一定会导致出现异常。
213
214相反,它可能会返回空数据集、报告错误或以其他方式表现出异常行为。
215例如,如果您未经许可查询日历,则该方法会返回空数据集。
216
217</p>
218
219<p>
220  如果您在未运行 M 预览版的设备上使用新权限模型安装应用,则系统将采用与其他任何应用相同的方式处理:系统会在安装应用时要求用户授予声明的所有权限。
221
222
223
224</p>
225
226<p class="note">
227  <strong>注:</strong>对于预览版本,您必须将最低 SDK 版本设置为 M 预览版 SDK,才可使用预览版 SDK 进行编译。
228这意味着在开发者预览版运行期间,您无法在旧版平台上测试此类应用。
229
230
231</p>
232
233<h3 id="perms-vs-intents">权限与意向的比较</h3>
234
235<p>
236  许多情况下,您可以使用以下两种方式之一来让您的应用执行某项任务。
237您可以将应用设置为请求执行操作本身所需的权限。
238或者,您可以将应用设置为通过传送意向,让其他应用来执行任务。
239
240</p>
241
242<p>
243  例如,假设应用需要能够使用设备相机拍摄照片。
244应用可以请求
245<code>android.permission.CAMERA</code> 权限,以便允许其直接访问相机。
246然后,应用将使用 Camera API 控制相机并拍摄照片。
247利用此方法,您的应用能够完全控制摄影过程,并支持您将相机 UI 合并至应用中。
248
249
250</p>
251
252<p>
253  但是,如果您无需此类控制,则可仅使用 {@link
254  android.provider.MediaStore#ACTION_IMAGE_CAPTURE ACTION_IMAGE_CAPTURE} 意向来请求图像。
255启动该意向时,系统会提示用户选择相机应用(如果没有默认相机应用),然后该应用将拍摄照片。
256
257该相机应用会将照片返回给应用的 {@link
258  android.app.Activity#onActivityResult onActivityResult()} 方法。
259</p>
260
261<p>
262  同样,如果您需要打电话、访问用户的联系人或要执行其他操作,则可通过创建适当的意向来完成,或者您可以请求相应的权限并直接访问相应的对象。
263
264每种方法各有优缺点。
265
266</p>
267
268<p>
269  如果使用权限:
270</p>
271
272<ul>
273  <li>应用可在您执行操作时完全控制用户体验。
274但是,如此广泛的控制会增加任务的复杂性,因为您需要设计适当的 UI。
275
276  </li>
277
278  <li>当您首次执行操作时,系统会显示一次让用户授予权限的提示。
279之后,应用即可执行操作,不再需要用户进行其他交互。
280但是,如果用户不授予权限(或稍后撤销权限),则应用根本无法执行操作。
281
282
283  </li>
284</ul>
285
286<p>
287  如果使用意向:
288</p>
289
290<ul>
291  <li>您无需为操作设计 UI。处理意向的应用将提供 UI。不过这意味着您无法控制用户体验。
292
293用户可以与您从未见过的应用进行交互。
294
295  </li>
296
297  <li>如果用户没有适用于操作的默认应用,则系统会提示用户选择应用。如果用户未指定默认处理程序,则必须在每次执行此操作时额外处理一个对话框。
298
299
300
301  </li>
302</ul>
303
304<h2 id="coding">为运行时权限编码</h2>
305
306<p>
307  如果应用主要面向新的 M 开发者预览版,则您必须使用新权限模型。
308这意味着除了通过清单文件声明所需的权限以外,您还必须检查应用运行时是否已有相应的权限,如果没有,则需要请求权限。
309
310
311
312</p>
313
314<h3 id="enabling">
315  启用新权限模型
316</h3>
317
318<p>
319  要启用新的 M 开发者预览版权限模型,请将应用的
320<code>targetSdkVersion</code> 属性设置为 <code>"MNC"</code>,并将
321<code>compileSdkVersion</code> 设置为 <code>"android-MNC"</code>。这样可启用所有新的权限功能。
322
323</p>
324
325<p>
326  对于预览版本,您必须将 <code>minSdkVersion</code> 设置为
327<code>"MNC"</code>,才能使用预览版 SDK 进行编译。
328</p>
329
330<h3 id="m-only-perm">
331  指定仅用于 M 预览版的权限
332</h3>
333
334<p>
335  您可以使用应用清单文件中的新 <code>&lt;uses-permission-sdk-m&gt;</code> 元素指明仅在 M 开发者预览版中需要某权限。
336如果您以这种方式声明权限,则每当在旧版设备上安装应用时,系统都不会提示用户或向应用授予权限。通过使用 <code>&lt;uses-permission-sdk-m&gt;</code>
337 元素,您可以将新权限添加到更新后的应用版本,而不必强制用户在安装更新时授予权限。
338
339
340
341
342
343</p>
344
345<p>
346  如果应用在已安装 M 开发者预览版的设备上运行,则
347<code>&lt;uses-permission-sdk-m&gt;</code> 的行为与
348<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code> 相同。
349  系统不会在安装应用时提示用户授予任何权限,且应用将根据需要请求权限。
350
351</p>
352
353<h3 id="prompting">
354  提示授予权限
355</h3>
356
357<p>
358  如果应用使用新的 M 开发者预览版权限模型,则在运行 M 预览版的设备上首次启动应用时,系统不会要求用户授予所有权限。
359
360相反,应用将根据需要请求权限。
361当应用请求某权限时,系统会向用户显示一个对话框。
362
363</p>
364
365<p>
366  如果应用在已安装 SDK 22 或更低版本的设备上运行,则应用将使用旧权限模型。
367当用户安装应用时,系统将提示他们授予应用在清单文件中请求的所有权限,但那些带有 <code>&lt;uses-permission-sdk-m&gt;</code> 标记的权限除外。
368
369
370</p>
371
372<h4 id="check-platform">检查运行应用的平台</h4>
373
374<p>
375  只有运行 M 开发者预览版的设备支持此权限模型。
376在调用其中任何方法之前,应用均应通过检查 {@link android.os.Build.VERSION#CODENAME
377  Build.VERSION.CODENAME} 的值来验证运行应用的平台。
378
379如果设备正在运行 M 开发者预览版,则
380{@link android.os.Build.VERSION#CODENAME CODENAME} 为 <code>"MNC"</code>。
381</p>
382
383<h4 id="check-for-permission">检查应用是否具备所需的权限</h4>
384
385<p>当用户尝试执行需要权限的操作时,应用将检查目前是否具备执行此操作所需的权限。
386为此,应用将调用
387<code>Context.checkSelfPermission(
388<i>permission_name</i>)</code>。即便知道用户已授予该权限,应用也应执行此检查,因为用户可以随时撤销应用的权限。
389
390
391例如,如果用户需要使用应用拍摄照片,则应用将调用
392<code>Context.checkSelfPermission(Manifest.permission.CAMERA)</code>。
393</p>
394
395<p class="table-caption" id="permission-groups">
396  <strong>表 1.</strong>权限和权限组。</p>
397<table>
398  <tr>
399    <th scope="col">权限组</th>
400    <th scope="col">权限</th>
401  </tr>
402
403  <tr>
404    <td><code>android.permission-group.CALENDAR</code></td>
405    <td>
406      <ul>
407        <li>
408          <code>android.permission.READ_CALENDAR</code>
409        </li>
410      </ul>
411      <ul>
412        <li>
413          <code>android.permission.WRITE_CALENDAR</code>
414        </li>
415      </ul>
416    </td>
417  </tr>
418
419  <tr>
420    <td><code>android.permission-group.CAMERA</code></td>
421    <td>
422      <ul>
423        <li>
424          <code>android.permission.CAMERA</code>
425        </li>
426      </ul>
427    </td>
428  </tr>
429
430  <tr>
431    <td><code>android.permission-group.CONTACTS</code></td>
432    <td>
433      <ul>
434        <li>
435          <code>android.permission.READ_CONTACTS</code>
436        </li>
437        <li>
438          <code>android.permission.WRITE_CONTACTS</code>
439        </li>
440        <li>
441          <code>android.permission.READ_PROFILE</code>
442        </li>
443        <li>
444          <code>android.permission.WRITE_PROFILE</code>
445        </li>
446      </ul>
447    </td>
448  </tr>
449
450  <tr>
451    <td><code>android.permission-group.LOCATION</code></td>
452    <td>
453      <ul>
454        <li>
455          <code>android.permission.ACCESS_FINE_LOCATION</code>
456        </li>
457        <li>
458          <code>android.permission.ACCESS_COARSE_LOCATION</code>
459        </li>
460      </ul>
461    </td>
462  </tr>
463
464  <tr>
465    <td><code>android.permission-group.MICROPHONE</code></td>
466    <td>
467      <ul>
468        <li>
469          <code>android.permission.RECORD_AUDIO</code>
470        </li>
471      </ul>
472    </td>
473  </tr>
474
475  <tr>
476    <td><code>android.permission-group.PHONE</code></td>
477    <td>
478      <ul>
479        <li>
480          <code>android.permission.READ_PHONE_STATE</code>
481        </li>
482        <li>
483          <code>android.permission.CALL_PHONE</code>
484        </li>
485        <li>
486          <code>android.permission.READ_CALL_LOG</code>
487        </li>
488        <li>
489          <code>android.permission.WRITE_CALL_LOG</code>
490        </li>
491        <li>
492          <code>com.android.voicemail.permission.ADD_VOICEMAIL</code>
493        </li>
494        <li>
495          <code>android.permission.USE_SIP</code>
496        </li>
497        <li>
498          <code>android.permission.PROCESS_OUTGOING_CALLS</code>
499        </li>
500      </ul>
501    </td>
502  </tr>
503
504  <tr>
505    <td><code>android.permission-group.SENSORS</code></td>
506    <td>
507      <ul>
508        <li>
509          <code>android.permission.BODY_SENSORS</code>
510        </li>
511      </ul>
512      <ul>
513        <li>
514          <code>android.permission.USE_FINGERPRINT</code>
515        </li>
516      </ul>
517    </td>
518  </tr>
519
520  <tr>
521    <td><code>android.permission-group.SMS</code></td>
522    <td>
523      <ul>
524        <li>
525          <code>android.permission.SEND_SMS</code>
526        </li>
527        <li>
528          <code>android.permission.RECEIVE_SMS</code>
529        </li>
530        <li>
531          <code>android.permission.READ_SMS</code>
532        </li>
533        <li>
534          <code>android.permission.RECEIVE_WAP_PUSH</code>
535        </li>
536        <li>
537          <code>android.permission.RECEIVE_MMS</code>
538        </li>
539        <li>
540          <code>android.permission.READ_CELL_BROADCASTS</code>
541        </li>
542      </ul>
543    </td>
544  </tr>
545
546</table>
547
548<h4 id="request-permissions">根据需要请求权限</h4>
549
550<p>如果应用尚无所需的权限,则应用将调用
551<code>Activity.requestPermissions(String[], int)</code> 方法,请求提供一项或多项适当的权限。
552应用将传递所需的一项或多项权限,以及整数“请求代码”。
553
554  此方法异步运行:它会立即返回,并且在用户响应对话框之后,系统会使用结果调用应用的回调方法,将应用传递的相同“请求代码”传递到 <code>requestPermissions()</code>。
555
556
557</p>
558
559  <p>以下代码检查应用是否具备读取用户联系人所需的权限,并根据需要请求该权限:
560</p>
561
562<pre>
563if (checkSelfPermission(Manifest.permission.READ_CONTACTS)
564        != PackageManager.PERMISSION_GRANTED) {
565    requestPermissions(new String[]{Manifest.permission.READ_CONTACTS},
566            MY_PERMISSIONS_REQUEST_READ_CONTACTS);
567
568    // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
569    // app-defined int constant
570
571    return;
572}
573</pre>
574
575<h4 id="handle-response">处理权限请求响应</h4>
576
577<p>
578  当应用请求权限时,系统将向用户显示一个对话框。
579当用户响应时,系统将调用应用的
580<code>Activity.onRequestPermissionsResult(int, String[], int[])</code>
581,向其传递用户响应。应用需要替代该方法。回调会将您传递的相同请求代码传递给
582<code>requestPermissions()</code>。
583例如,如果应用请求
584<code>READ_CONTACTS</code> 访问权限,则可能采用以下回调方法:
585
586</p>
587
588<pre>
589&#64;Override
590public void onRequestPermissionsResult(int requestCode,
591        String permissions[], int[] grantResults) {
592    switch (requestCode) {
593        case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
594            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
595
596                // permission was granted, yay! do the
597                // calendar task you need to do.
598
599            } else {
600
601                // permission denied, boo! Disable the
602                // functionality that depends on this permission.
603            }
604            return;
605        }
606
607        // other 'switch' lines to check for other
608        // permissions this app might request
609    }
610}
611</pre>
612
613  <p>如果用户授予权限,则系统会为应用授予应用清单文件为该功能区域列出的所有权限。
614如果用户拒绝请求,则您应采取适当的操作。
615例如,您可以禁用任何取决于此权限的菜单操作。
616
617  </li>
618</p>
619
620<p>
621  当系统要求用户授予权限时,用户可以选择指示系统不再要求提供该权限。
622在这种情况下,当应用使用 <code>requestPermissions()</code> 请求该权限时,系统会立即拒绝此请求。
623
624在这种情况下,如果用户已再次明确拒绝您的请求,则系统会以同样的方式调用您的 <code>onRequestPermissionsResult()</code>。
625
626因此,您的应用不能假设用户采取了任何直接交互行为。
627
628</p>
629
630<h2 id="testing">测试运行时权限</h2>
631
632
633<p>
634  如果应用主要面向 M 开发者预览版,则您必须测试它是否正确处理权限。
635您不能假设应用在运行时具备任何特定的权限。
636应用首次启动时,它可能没有任何权限,且用户可以随时撤销或恢复权限。
637
638
639</p>
640
641<p>
642  您应测试应用,确保它在所有权限情况下均可正常运行。
643通过 M 预览版 SDK,我们提供了新的
644<a href="{@docRoot}tools/help/adb.html">Android
645  Debug Bridge (adb)</a> 命令,支持您使用需要尝试的任何权限设置测试应用。
646
647</p>
648
649<h3>
650  新 adb 命令和选项
651</h3>
652
653<p>
654  M 预览版 SDK 平台工具提供了多个新命令,支持您测试应用处理权限的方式。
655
656</p>
657
658<h4>
659  使用权限安装
660</h4>
661
662<p>
663  您可以使用 <a href="{@docRoot}tools/help/adb.html#move"><code>adb
664  install</code></a> 命令的新 <code>-g</code> 选项,该选项将安装应用并授予其清单文件中列出的所有权限:
665
666</p>
667
668<pre class="no-pretty-print">
669$ adb install -g &lt;path_to_apk&gt;
670</pre>
671
672<h4>
673  授予和撤销权限
674</h4>
675
676<p>
677  您可以使用新的 ADB <a href="{@docRoot}tools/help/adb.html#pm">软件包管理器 (pm)</a> 命令向已安装的应用授予权限和撤销其权限。此功能对于自动化测试非常有用。
678
679
680</p>
681
682<p>
683  要授予权限,请使用软件包管理器的 <code>grant</code> 命令:
684</p>
685
686<pre class="no-pretty-print">
687$ adb pm grant &lt;package_name&gt; &lt;permission_name&gt;
688</pre>
689
690<p>
691  例如,要向录音​​授予 com.example.myapp 软件包权限,请使用以下命令:
692
693</p>
694
695<pre class="no-pretty-print">
696$ adb pm grant com.example.myapp android.permission.RECORD_AUDIO
697</pre>
698
699<p>
700  要撤销权限,请使用软件包管理器的 <code>revoke</code> 命令:
701</p>
702
703<pre class="no-pretty-print">
704$ adb pm revoke &lt;package_name&gt; &lt;permission_name&gt;
705</pre>
706
707<h2 id="best-practices">最佳做法</h2>
708
709<p>
710  新权限模型为用户带来更流畅的体验,让他们能够更轻松地安装应用,并得心应手地使用应用的各项功能。
711
712为了充分利用该新模型,我们建议采用下列最佳做法。
713
714</p>
715
716
717<h3 id="bp-what-you-need">仅请求自己所需的权限</h3>
718
719<p>
720  每次您请求权限时,实际上是在强迫用户作出决定。
721  如果用户拒绝请求,则会减少应用的功能。
722  您应尽量减少提出这些请求的次数。
723</p>
724
725<p>
726  例如,应用往往可以通过使用
727<a href="{@docRoot}guide/components/intents-filters.html">意向</a>(而不是请求权限)获得所需的功能。
728如果应用需要使用手机的相机拍摄照片,则可使用
729 {@link
730  android.provider.MediaStore#ACTION_IMAGE_CAPTURE
731  MediaStore.ACTION_IMAGE_CAPTURE} 意向。当应用执行该意向时,系统会提示用户选择已安装的相机应用拍摄照片。
732
733
734</p>
735
736<h3 id="bp-dont-overwhelm">
737  不要让用户感到无所适从
738</h3>
739
740<p>
741  如果您让用户一次面对大量权限请求,用户可能会感到无所适从并因此退出应用。替代做法是,您应根据需要请求权限。
742
743
744</p>
745
746<p>
747  某些情况下,您的应用可能绝对需要一项或多项权限。在这种情况下,合理的做法是,在应用启动之后立即请求所有权限。
748
749例如,如果您运行摄影应用,则该应用需要访问设备的相机。
750当用户首次启动该应用时,不会对请求使用相机所需的权限感到惊讶。
751
752但是,如果同一应用还具备与用户联系人共享照片的功能,则您不应在首次启动时请求用户提供该权限,<em></em>
753
754而是等到用户尝试使用“共享”功能之后,再请求该权限。
755
756</p>
757
758<p>
759  如果应用提供了教程,则合理的做法是,在教程结束时请求提供应用的必要权限。
760
761</p>
762
763<h3 id="bp-explain">
764  解释需要权限的原因
765</h3>
766
767<p>
768  系统在您调用
769<code>requestPermissions()</code> 时显示的权限对话框将说明应用所需的权限,但不会解释为何需要这些权限。
770在某些情况下,用户可能会感到困惑。
771  最好在调用 <code>requestPermissions()</code> 之前向用户解释应用需要权限的原因。
772
773</p>
774
775<p>
776  例如,摄影应用可能需要使用位置服务,以便能够为照片添加地理标签。
777通常,用户可能不了解照片能够包含位置信息,并且对摄影应用想要了解具体位置感到不解。
778
779因此在这种情况下,应用最好在调用
780<code>requestPermissions()</code> 之前告知此功能的相关信息。<em></em>
781
782</p>
783
784<p>
785  其中一种办法是将这些请求纳入应用教程。这样,教程可以依次显示应用的每项功能,并在显示每项功能时解释需要哪些相应的权限。
786
787例如,摄影应用的教程可以演示其“与您的联系人共享照片”功能,然后告知用户需要为应用授予权限以便其查看用户的联系人。
788
789
790然后,应用可以调用 <code>requestPermissions()</code>,要求用户提供该访问权限。
791当然,并非所有用户都会按照教程操作,因此您仍需在应用的正常操作期间检查和请求权限。
792
793
794</p>
795