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>应用 ></strong> 191 192 <i>应用名称</i> <strong>> 权限</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><uses-permission-sdk-m></code> 元素指明仅在 M 开发者预览版中需要某权限。 336如果您以这种方式声明权限,则每当在旧版设备上安装应用时,系统都不会提示用户或向应用授予权限。通过使用 <code><uses-permission-sdk-m></code> 337 元素,您可以将新权限添加到更新后的应用版本,而不必强制用户在安装更新时授予权限。 338 339 340 341 342 343</p> 344 345<p> 346 如果应用在已安装 M 开发者预览版的设备上运行,则 347<code><uses-permission-sdk-m></code> 的行为与 348<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html"><uses-permission></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><uses-permission-sdk-m></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@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 <path_to_apk> 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 <package_name> <permission_name> 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 <package_name> <permission_name> 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