位置权限关闭后，如何实现在应用内一步操作重新开启
========================

#### 问题现象

位置权限被关闭后，如何引导用户开启精确位置和后台位置权限，减少操作路径，优化用户体验？

#### 背景知识

位置权限说明：

| 
场景

 | 

涉及权限

 | 

备注

 |
| :-- | :-- | :-- |
| 

模糊位置

 | 

[ohos.permission.APPROXIMATELY\_LOCATION](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/permissions-for-all-user#ohospermissionapproximately_location)

 | 

精确度为5公里。

 |
| 

精确位置

 | 

[ohos.permission.LOCATION](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/permissions-for-all-user#ohospermissionlocation)

 | 

精确度为米级，需要与ohos.permission.APPROXIMATELY\_LOCATION同时申请。

 |
| 

后台位置

 | 

[ohos.permission.LOCATION\_IN\_BACKGROUND](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/permissions-for-all-user#ohospermissionlocation_in_background)

 | 

先获取前台位置权限，再配合[长时任务](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/continuous-task)使用。

 |

![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/10/v3/_MS-6NO1R5qU2-JB8qiYlw/note_3.0-zh-cn.png?HW-CC-KV=V1&HW-CC-Date=20260709T134319Z&HW-CC-Expire=86400&HW-CC-Sign=2F00F5D7F2785BAF935B4D2A0C3C5CBCE40863CB8AF797BEB212067E976D7C8D)

*   精确位置：关闭“精确位置”的开关后，无法通过[requestPermissionsFromUser()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-abilityaccessctrl#requestpermissionsfromuser9)再次拉起弹框获取授权。需要用户手动在设置中开启，或者使用[requestPermissionOnSetting()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-abilityaccessctrl#requestpermissiononsetting12)接口[二次向用户申请授权](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/request-user-authorization-second)。
*   后台位置：申请后台权限前，必须先申请前台位置权限。前台位置权限的申请有两种允许情况：
    *   申请前台模糊位置权限：ohos.permission.APPROXIMATELY\_LOCATION。
    *   申请前台精确位置权限：ohos.permission.APPROXIMATELY\_LOCATION和ohos.permission.LOCATION。

#### 解决方案

*   **场景一****：****代码引导用户开启“精确位置”**。
    1.  使用[checkAccessTokenSync()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-abilityaccessctrl#checkaccesstokensync10)接口判断ohos.permission.LOCATION是否授权的方式，确认当前应用是否开启“精确位置”开关。
        
        checkPermissionGrant(): void {
          let hasPermission \= false;
          let tokenId: number \= 0;
          try {
            let bundleInfo: bundleManager.BundleInfo \=
              bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET\_BUNDLE\_INFO\_WITH\_APPLICATION);
            let appInfo: bundleManager.ApplicationInfo \= bundleInfo.appInfo;
            tokenId \= appInfo.accessTokenId;
          } catch (error) {
            const err: BusinessError \= error as BusinessError;
            hilog.error(0x0000, 'Index',
              \`Failed to get bundle info for self. Code is ${err.code}, message is ${err.message}\`);
          }
        
          try {
            let atManager \= abilityAccessCtrl.createAtManager();
            let approximatelyLocation \= atManager.checkAccessTokenSync(tokenId, 'ohos.permission.APPROXIMATELY\_LOCATION');
           _ // 获取精确位置权限授权状态_
            let location \= atManager.checkAccessTokenSync(tokenId, 'ohos.permission.LOCATION');
            hasPermission \= approximatelyLocation \=== abilityAccessCtrl.GrantStatus.PERMISSION\_GRANTED &&
              location \=== abilityAccessCtrl.GrantStatus.PERMISSION\_GRANTED;
          } catch (error) {
            const err: BusinessError \= error as BusinessError;
            hilog.error(0x0000, 'Index', \`Failed to check access token. Code is ${err.code}, message is ${err.message}\`);
          }
          if (hasPermission) {
            this.isLocationToggle();
          } else {
            this.requestPermissions();
          }
        }
        
    2.  在[requestPermissionsFromUser()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-abilityaccessctrl#requestpermissionsfromuser9)申请授权回调中判断是否有授权弹窗提示。应用非首次申请授权且没有向用户展示授权弹框，应用可以调用[requestPermissionOnSetting()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-abilityaccessctrl#requestpermissiononsetting12)接口二次向用户申请位置授权。
        
        requestPermissions(): void {
          let atManager \= abilityAccessCtrl.createAtManager();
          try {
            atManager.requestPermissionsFromUser(this.context, \['ohos.permission.APPROXIMATELY\_LOCATION',
              'ohos.permission.LOCATION'\]).then((data) \=\> {
              if (data.authResults\[0\] \=== -1 || data.authResults\[1\] \=== -1) {
                if (data.dialogShownResults && (data.dialogShownResults\[0\] || data.dialogShownResults\[1\])) {
                  this.isShowPermissions \= true;
                  if (data.authResults\[0\] \=== -1) {
                    this.permissionsMessage \= '需获取定位权限才能正常使用';
                  } else {
                    this.permissionsMessage \= '需获取精确定位权限才能获取精确位置';
                  }
                } else {
                  this.openPermissionsSetting();
                  return;
                }
              } else {
                this.isShowPermissions \= false;
              }
              if (data.authResults\[0\] !== 0) {
                return;
              }
              this.isLocationToggle();
            }).catch((err: Error) \=\> {
              hilog.error(0x0000, 'Index', 'requestPermissionsFromUser err:' \+ JSON.stringify(err));
            });
          } catch (err) {
            hilog.error(0x0000, 'Index', 'requestPermissionsFromUser err:' \+ JSON.stringify(err));
          }
        }
        
    3.  使用[requestPermissionOnSetting()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-abilityaccessctrl#requestpermissiononsetting12)接口向用户二次申请“精确位置”授权。
        
        private openPermissionsSetting(): void {
          let atManager \= abilityAccessCtrl.createAtManager();
          atManager.requestPermissionOnSetting(this.context, \['ohos.permission.APPROXIMATELY\_LOCATION',
            'ohos.permission.LOCATION'\]).then((data: Array<abilityAccessCtrl.GrantStatus\>) \=\> {
            if (data\[0\] \=== -1 && data\[1\] \=== -1) {
              this.isShowPermissions \= true;
              this.permissionsMessage \= '需获取定位权限才能正常使用';
              return;
            } else if (data\[0\] \=== 0 && data\[1\] \=== -1) {
              this.isShowPermissions \= true;
              this.permissionsMessage \= '需获取精确定位权限才能获取精确位置';
            } else {
              this.isShowPermissions \= false;
            }
            this.isLocationToggle();
          }).catch((err: BusinessError) \=\> {
            hilog.error(0x0000, 'Index', 'data:' \+ JSON.stringify(err));
          });
        }
        
        效果预览：
        
        ![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/dc/v3/MNjw-MP3TP2m9KRg5-EGdw/zh-cn_image_0000002658793799.png?HW-CC-KV=V1&HW-CC-Date=20260709T134319Z&HW-CC-Expire=86400&HW-CC-Sign=797CE3D79501B5F114E0C8ECA39C803DDB2C37FF5239B34F49634A296D79341B "点击放大")
        
*   **场景二：代码引导用户开启“后台位置”。**
    
    确认完成前台位置权限授权后，使用[requestPermissionOnSetting()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-abilityaccessctrl#requestpermissiononsetting12)接口向用户申请后台位置授权：
    
    let atManager: abilityAccessCtrl.AtManager \= abilityAccessCtrl.createAtManager();
    atManager.requestPermissionOnSetting(this.context, \['ohos.permission.LOCATION\_IN\_BACKGROUND'\])
      .then((data: Array<abilityAccessCtrl.GrantStatus\>) \=\> {
        hilog.info(0x0000, 'Index', \`requestPermissionOnSetting success, result: ${data}\`);
      })
      .catch((err: BusinessError) \=\> {
        hilog.error(0x0000, 'Index',
          \`requestPermissionOnSetting fail, code: ${err.code}, message: ${err.message}\`);
        if (err.code \== 12100011) {
          try {
            this.promptAction.showToast({
              message: '已获取权限',
              duration: 2000
            });
          } catch (error) {
            let message \= (error as BusinessError).message;
            let code \= (error as BusinessError).code;
            hilog.error(0x0000, 'Index', \`showToast args error code is ${code}, message is ${message}\`);
          }
        }
      });
    
    效果预览：
    
    ![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/fc/v3/yvLwzKTlQkyn9ZzjzVZkyw/zh-cn_image_0000002628394530.png?HW-CC-KV=V1&HW-CC-Date=20260709T134319Z&HW-CC-Expire=86400&HW-CC-Sign=E224CAEF42C93550CFC58F25343441B436303037C2C600A333212E0D64482867 "点击放大")
    
*   **场景三：代码引导用户开启“系统位置”功能开关。**
    
    使用[isLocationEnabled()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-geolocationmanager#geolocationmanagerislocationenabled)检查当前系统位置功能是否被禁用。如果位置功能被禁用则无法获取位置信息，需要调用[requestGlobalSwitch()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-abilityaccessctrl#requestglobalswitch12)拉起半模态对话框打开位置开关。
    
    isLocationToggle(): void {
      let atManager \= abilityAccessCtrl.createAtManager();
      let isLocationEnabled \= geoLocationManager.isLocationEnabled();
      if (!isLocationEnabled) {
        atManager.requestGlobalSwitch(this.context, abilityAccessCtrl.SwitchType.LOCATION).then((data: boolean) \=\> {
          if (data) {
            this.isShowLocation \= false;
            this.getLocation();
          } else {
            this.isShowLocation \= true;
            this.locationServiceMessage \= '需打开设备位置服务才能获取当前位置';
          }
        }).catch((err: BusinessError) \=\> {
          hilog.error(0x0000, 'Index', 'data:' \+ JSON.stringify(err));
        });
      } else {
        this.isShowLocation \= false;
        this.getLocation();
      }
    }
    
    效果预览：
    
    ![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/1d/v3/N4J9IQeoQC6kXcerXeJWJg/zh-cn_image_0000002628554424.png?HW-CC-KV=V1&HW-CC-Date=20260709T134319Z&HW-CC-Expire=86400&HW-CC-Sign=C9F6F7E1FBE409FC3AFB9E335AB489A6899E72A0F7A5D9F4CDC730C50CBA6C67 "点击放大")
    

完整代码如下，使用前请先在module.json5中声明ohos.permission.APPROXIMATELY\_LOCATION、ohos.permission.LOCATION和ohos.permission.LOCATION\_IN\_BACKGROUND权限：

import { i18n } from '@kit.LocalizationKit';
import { abilityAccessCtrl, bundleManager, common } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { geoLocationManager } from '@kit.LocationKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { PromptAction } from '@kit.ArkUI';

@Entry
@Component
struct Index {
  @State isShowPermissions: boolean \= false;
  @State currentLocation: string \= '';
  @State permissionsMessage: string \= '需获取定位权限才能正常使用';
  @State locationServiceMessage: string \= '需获取定位权限才能正常使用';
  @State isShowLocation: boolean \= false;
  @Watch('locale') @StorageLink('language') systemLanguages: string \= i18n.System.getAppPreferredLanguage();
  private context: common.UIAbilityContext \= this.getUIContext().getHostContext() as common.UIAbilityContext;
  private promptAction: PromptAction \= this.getUIContext().getPromptAction();
  latitude: number \= 0;
  longitude: number \= 0;

  locale(): void {
    this.getLocation();
  }

  build() {
    Column({ space: 10 }) {
      Column() {
        Row() {
          Text('当前位置：')
            .fontSize(20)
            .fontWeight(FontWeight.Bolder)
            .textAlign(TextAlign.Start)
        }
        .width('100%')
        .padding({
          left: 12,
          right: 16
        })
        .margin({
          top: 16,
          bottom: 16
        })

        Row() {
          Text(this.currentLocation)
        }
        .width('100%')
        .padding({
          left: 16,
          right: 16
        })
      }

      Column() {
        if (this.isShowPermissions) {
          Text() {
            Span(this.permissionsMessage)
              .fontColor('#99000000')
            Span('开启权限')
              .fontColor('#0A59F7')
              .onClick(() \=\> {
                this.checkPermissionGrant();
              })
          }
          .width('100%')
          .padding({
            left: 16,
            right: 16
          })
          .margin({
            bottom: 16
          })
        }
        if (this.isShowLocation) {
          Text() {
            Span(this.locationServiceMessage)
              .fontColor('#99000000')
            Span('开启位置服务')
              .fontColor('#0A59F7')
              .onClick(() \=\> {
                this.isLocationToggle();
              })
          }
          .width('100%')
          .padding({
            left: 16,
            right: 16
          })
          .margin({
            bottom: 16
          })
        }

        Button('获取当前位置')
          .onClick(() \=\> {
            this.currentLocation \= '';
            this.checkPermissionGrant();
          })
          .backgroundColor('#0A59F7')
          .width(288)
          .margin({
            bottom: 16
          })

        if (this.isShowPermissions) {
          Button('开启后台位置权限')
            .onClick(() \=\> {
              let atManager: abilityAccessCtrl.AtManager \= abilityAccessCtrl.createAtManager();
              atManager.requestPermissionOnSetting(this.context, \['ohos.permission.LOCATION\_IN\_BACKGROUND'\])
                .then((data: Array<abilityAccessCtrl.GrantStatus\>) \=\> {
                  hilog.info(0x0000, 'Index', \`requestPermissionOnSetting success, result: ${data}\`);
                })
                .catch((err: BusinessError) \=\> {
                  hilog.error(0x0000, 'Index',
                    \`requestPermissionOnSetting fail, code: ${err.code}, message: ${err.message}\`);
                  if (err.code \== 12100011) {
                    try {
                      this.promptAction.showToast({
                        message: '已获取权限',
                        duration: 2000
                      });
                    } catch (error) {
                      let message \= (error as BusinessError).message;
                      let code \= (error as BusinessError).code;
                      hilog.error(0x0000, 'Index', \`showToast args error code is ${code}, message is ${message}\`);
                    }
                  }
                });
            })
            .backgroundColor('#0A59F7')
            .width(288)
            .margin({
              bottom: 16
            })
        }

      }
    }
    .justifyContent(FlexAlign.SpaceBetween)
    .width('100%')
    .height('100%')
  }

 _ // \[Start open\_permissions\_setting\]_
  _// The permission setting dialog box is displayed._
  private openPermissionsSetting(): void {
    let atManager \= abilityAccessCtrl.createAtManager();
    atManager.requestPermissionOnSetting(this.context, \['ohos.permission.APPROXIMATELY\_LOCATION',
      'ohos.permission.LOCATION'\]).then((data: Array<abilityAccessCtrl.GrantStatus\>) \=\> {
      if (data\[0\] \=== -1 && data\[1\] \=== -1) {
        this.isShowPermissions \= true;
        this.permissionsMessage \= '需获取定位权限才能正常使用';
        return;
      } else if (data\[0\] \=== 0 && data\[1\] \=== -1) {
        this.isShowPermissions \= true;
        this.permissionsMessage \= '需获取精确定位权限才能获取精确位置';
      } else {
        this.isShowPermissions \= false;
      }
      this.isLocationToggle();
    }).catch((err: BusinessError) \=\> {
      hilog.error(0x0000, 'Index', 'data:' \+ JSON.stringify(err));
    });
  }

  _// \[End open\_permissions\_setting\]_

  _// \[Start check\_permission\_grant\]_
  _// Verify if the application has been granted permission._
  checkPermissionGrant(): void {
    let hasPermission \= false;
    let tokenId: number \= 0;
    try {
      let bundleInfo: bundleManager.BundleInfo \=
        bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET\_BUNDLE\_INFO\_WITH\_APPLICATION);
      let appInfo: bundleManager.ApplicationInfo \= bundleInfo.appInfo;
      tokenId \= appInfo.accessTokenId;
    } catch (error) {
      const err: BusinessError \= error as BusinessError;
      hilog.error(0x0000, 'Index',
        \`Failed to get bundle info for self. Code is ${err.code}, message is ${err.message}\`);
    }

    try {
      let atManager \= abilityAccessCtrl.createAtManager();
      let approximatelyLocation \= atManager.checkAccessTokenSync(tokenId, 'ohos.permission.APPROXIMATELY\_LOCATION');
     _ // 获取精确位置权限授权状态_
      let location \= atManager.checkAccessTokenSync(tokenId, 'ohos.permission.LOCATION');
      hasPermission \= approximatelyLocation \=== abilityAccessCtrl.GrantStatus.PERMISSION\_GRANTED &&
        location \=== abilityAccessCtrl.GrantStatus.PERMISSION\_GRANTED;
    } catch (error) {
      const err: BusinessError \= error as BusinessError;
      hilog.error(0x0000, 'Index', \`Failed to check access token. Code is ${err.code}, message is ${err.message}\`);
    }
    if (hasPermission) {
      this.isLocationToggle();
    } else {
      this.requestPermissions();
    }
  }

  _// \[End check\_permission\_grant\]_

  _// \[Start request\_permissions\]_
  _// Requests location permissions from the user._
  requestPermissions(): void {
    let atManager \= abilityAccessCtrl.createAtManager();
    try {
      atManager.requestPermissionsFromUser(this.context, \['ohos.permission.APPROXIMATELY\_LOCATION',
        'ohos.permission.LOCATION'\]).then((data) \=\> {
        if (data.authResults\[0\] \=== -1 || data.authResults\[1\] \=== -1) {
          if (data.dialogShownResults && (data.dialogShownResults\[0\] || data.dialogShownResults\[1\])) {
            this.isShowPermissions \= true;
            if (data.authResults\[0\] \=== -1) {
              this.permissionsMessage \= '需获取定位权限才能正常使用';
            } else {
              this.permissionsMessage \= '需获取精确定位权限才能获取精确位置';
            }
          } else {
            this.openPermissionsSetting();
            return;
          }
        } else {
          this.isShowPermissions \= false;
        }
        if (data.authResults\[0\] !== 0) {
          return;
        }
        this.isLocationToggle();
      }).catch((err: Error) \=\> {
        hilog.error(0x0000, 'Index', 'requestPermissionsFromUser err:' \+ JSON.stringify(err));
      });
    } catch (err) {
      hilog.error(0x0000, 'Index', 'requestPermissionsFromUser err:' \+ JSON.stringify(err));
    }
  }

 _ // \[End request\_permissions\]_

  _// \[Start is\_location\_toggle\]_
  _// Obtain current location switch status and pull up the global switch to set the pop-up box._
  isLocationToggle(): void {
    let atManager \= abilityAccessCtrl.createAtManager();
    let isLocationEnabled \= geoLocationManager.isLocationEnabled();
    if (!isLocationEnabled) {
      atManager.requestGlobalSwitch(this.context, abilityAccessCtrl.SwitchType.LOCATION).then((data: boolean) \=\> {
        if (data) {
          this.isShowLocation \= false;
          this.getLocation();
        } else {
          this.isShowLocation \= true;
          this.locationServiceMessage \= '需打开设备位置服务才能获取当前位置';
        }
      }).catch((err: BusinessError) \=\> {
        hilog.error(0x0000, 'Index', 'data:' \+ JSON.stringify(err));
      });
    } else {
      this.isShowLocation \= false;
      this.getLocation();
    }
  }

  getLocation(): void {
    let request: geoLocationManager.SingleLocationRequest \= {
      'locatingTimeoutMs': 10000,
      'locatingPriority': geoLocationManager.LocatingPriority.PRIORITY\_LOCATING\_SPEED
    };
  _  // Get current location._
    geoLocationManager.getCurrentLocation(request).then((location) \=\> {
      this.latitude \= location.latitude;
      this.longitude \= location.longitude;
      let reverseGeocodeRequest: geoLocationManager.ReverseGeoCodeRequest \= {
        'locale': this.systemLanguages.toString().includes('zh') ? 'zh' : 'en',
        'latitude': this.latitude,
        'longitude': this.longitude,
        'maxItems': 1
      };
     _ // Call the inverse geocoding service to convert coordinates into geographic descriptions._
      geoLocationManager.getAddressesFromLocation(reverseGeocodeRequest).then((data) \=\> {
        if (data\[0\].placeName) {
          this.currentLocation \= data\[0\].placeName;
        }
      }).catch((err: BusinessError) \=\> {
        hilog.error(0x0000, 'Index', 'GetAddressesFromLocation err:' \+ JSON.stringify(err));
      });
    }).catch((err: BusinessError) \=\> {
      hilog.error(0x0000, 'Index', 'Promise getCurrentLocation err:' \+ JSON.stringify(err));
    });
  }

 _ // \[End is\_location\_toggle\]_
}

#### 常见FAQ

Q：申请ohos.permission.LOCATION精确位置无弹窗提示。

A：ohos.permission.LOCATION不可以单独申请，需要与模糊位置权限ohos.permission.APPROXIMATELY\_LOCATION同时申请。

Q：位置授权弹窗三种选择对应的效果是什么。

A：位置授权弹窗提示分为以下三种情况：

*   不允许：后续不再弹窗，如需要权限，需要提醒用户前往设置页面手动开启；
*   本次使用允许：赋予临时权限，后续再次调用[requestPermissionsFromUser()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-abilityaccessctrl#requestpermissionsfromuser9)向用户索取权限时，还会继续弹窗；
*   仅在使用期间允许：应用在前台使用位置权限不再弹窗提醒。

Q：是否可以区分用户选择了位置授权弹框的“不允许”、“本次允许”还是“仅在使用期间允许”？

A：[checkAccessTokenSync](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-abilityaccessctrl#checkaccesstokensync10)接口仅返回是否授权两个枚举状态[GrantStatus](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-abilityaccessctrl#grantstatus)，不会进一步说明选择的是哪种授权类型。

Q：如何取消位置权限的授权？

A：参考上述场景二，代码引导用户关闭“后台位置”。

Q：精确位置默认能否开启？

A：精确位置权限默认是关闭的，开发者必须显式声明和申请权限。