微信小程序中用户拒绝授权的处理方式

前言
最近一段时间在研究微信小程序的开发,相比于原生app来说,确实上手要容易不少,也能够提升项目的开发速度。但与此同时,小程序开发中也存在一些“坑”需要我们注意,因此我想记录一下自己在微信小程序开发中遇到的一些问题,方便日后查阅。

微信小程序中的权限介绍

大家如果接触过移动开发应该都知道,涉及到一些用户敏感信息的操作(比如定位、访问本地文件等)都是需要用户授权的,在Android开发中,我们需要提前将这些权限配置到项目中,Android 6.0及以上版本还需要通过代码来动态申请部分权限。微信小程序也是如此,我们平时使用小程序时可能也见到过进行某个操作之前弹出授权框的场景,需要用户手动授权后才能进行下一步操作。接下来我简单介绍一下微信小程序中的授权机制,基本上都是参考自官方文档,大家也可以直接阅读官方文档,了解更详细的介绍。
微信小程序中所有需要授权的操作和对应的权限关系如下表:

权限说明 对应接口
scope.userInfo(获取用户信息) wx.getUserInfo
scope.userLocation(获取地理位置信息) wx.getLocation, wx.chooseLocation
scope.userLocationBackground(后台定位) wx.startLocationUpdateBackground
scope.record(录音) wx.startRecord
scope.writePhotosAlbum(保存文件到相册) wx.saveImageToPhotosAlbum, wx.saveVideoToPhotosAlbum
scope.camera(调用系统摄像头) camera组件
scope.werun(获取微信运动步数) wx.getWeRunData
scope.address(获取收货地址) wx.chooseAddress
scope.invoiceTitle(获取发票抬头) wx.chooseInvoiceTitle
scope.invoice(获取发票信息) wx.chooseInvoice

和Android开发不同的是,微信小程序不需要通过代码来申请权限,在调用上述接口时会自动弹出授权框让用户进行授权。但是需要注意的是,一旦用户选择了拒绝或者允许该权限,那么授权关系就会被记录在后台,直到用户主动删除小程序,之后再次调用该API时都不会再弹出权限申请框。如果用户拒绝了授权,之后调用该API都会失败(执行对应的fail回调),因此我们要根据实际的开发场景处理好用户拒绝授权的情况,如果API的返回值是必需的,那么我们就要在用户拒绝授权后引导用户手动开启该权限从而保证API的成功调用。下面我就以获取位置信息API(wx.getLocation)为例,介绍一下如何处理用户拒绝授权的情况。

如何处理用户拒绝授权的情况

下面就以调用wx.getLocation()获取用户位置信息为例介绍一下用户拒绝授权的处理方式。scope.userLocationscope.userLocationBackground权限比较特殊,需要在小程序根目录下的app.json文件中配置位置信息的用途说明,如下所示:

"permission": {
  "scope.userLocation": {
    "desc": "您的位置信息将用于定位"
  }
}

其中的"desc"就是展示给用户的位置信息用途说明,之后在调用wx.getLocation()时就会弹出如下授权提示框。

当然具体的弹窗样式会和手机系统以及微信版本有关,但是弹窗展示的内容是不变的。根据此前的介绍,当用户点击了“拒绝”后,此后调用wx.getLocation()时都会执行fail失败回调,无法获取用户位置信息,因此我们可以在fail回调中判断用户是否拒绝了授权,对于用户拒绝授权的情况调用wx.openSetting跳转小程序设置页面,引导用户手动开启该权限。判断用户是否拒绝授权的方式有以下两种:

  • 通过wx.getSetting获取用户当前的授权状态来判断

我们可以在wx.getLocation的fail回调中调用wx.getSetting来获取用户当前授权状态,从而判断用户是否拒绝了定位权限,示例代码如下:

wx.getLocation({
  success: res => {
    console.log(res);
  },
  fail: e => {
    console.log(e);
    // 判断用户是否拒绝了授权
    wx.getSetting({
      success: res => {
        if (typeof(res.authSetting['scope.userLocation']) != 'undefined' && !res.authSetting['scope.userLocation']) {
          // 用户拒绝了授权,跳转设置页面
          
        }
      }
    });
  }
});

大家可能会有疑问,为什么不能直接根据!res.authSetting['scope.userLocation']来判断呢?这是因为wx.getSetting的返回值中只会出现小程序已经向用户申请过的权限,换句话说,只有此前弹出过权限申请框,并且用户点击了“拒绝”或者“允许”,之后在wx.getSetting的success回调中才能获取到res.authSetting['scope.userLocation']的值。我们可以考虑这样一种情况,当调用wx.getLocation弹出权限申请框后,用户没有点击“拒绝”或“允许”按钮,而是通过系统返回键关闭了权限申请框,之后也会执行fail回调,但是此时res.authSetting中是没有scope.userLocation属性的,同样满足!res.authSetting['scope.userLocation']条件,这种情况跳转设置页面是不太符合逻辑的。还有一个重要的原因,wx.openSetting同样只会显示小程序已经向用户申请过的权限,因此这种情况即使跳转了设置页面,页面中也不会显示出该权限,当然也无法引导用户手动开启了。

  • 通过返回的错误信息来判断

我们也可以通过wx.getLocation的fail回调返回的错误信息来判断用户是否拒绝了定位权限。拒绝授权返回的错误信息官方文档中并没有写,我们只能通过测试来得到,经过我个人的测试,拒绝定位权限返回的错误信息如下:

微信开发者工具:getLocation:fail auth deny
Android手机用户点击授权框中的“拒绝”按钮:getLocation:fail:auth denied
Android手机用户已拒绝授权,之后每一次调用定位API:getLocation:fail auth deny
苹果手机用户点击授权框中的“拒绝”按钮:getLocation:fail auth deny
苹果手机用户已拒绝授权,之后每一次调用定位API:getLocation:fail authorize no response

这里就不得不吐槽一下了,其实一开始我只在开发工具上进行了测试,错误信息只考虑了一种,后来通过测试人员反馈我才知道原来这也和手机的系统有关,之后我测试了录音的API,也是同样的情况。我确实不能理解为什么同样的情况,不同手机系统返回的错误信息还要有所区别,不过既然小程序是这样设计的,可能也有它的道理吧,如果大家有什么见解或者是我的测试有什么不对的地方欢迎提出。
好了,回到正题,对于用户拒绝定位权限的情况,我们需要同时考虑这三种错误信息,示例代码如下:

wx.getLocation({
  success: res => {
    console.log(res);
  },
  fail: e => {
    console.log(e);
    // 判断用户是否拒绝了授权
    if (e.errMsg == 'getLocation:fail:auth denied' || e.errMsg == 'getLocation:fail auth deny' || e.errMsg == 'getLocation:fail authorize no response') {
      // 用户拒绝了授权,跳转设置页面
    }
  }
});

由于授权失败对应的错误信息是不唯一的,我也不清楚官方在之后是否会修改,因此我不是很推荐使用这种方式来判断。
之后对于用户拒绝授权的情况就可以调用wx.openSetting打开设置页面,引导用户手动开启权限了。

// 用户拒绝了授权,跳转设置页面
wx.openSetting({
  success: res => {
    if (res.authSetting['scope.userLocation']) {
      // 授权成功,重新定位
      wx.getLocation({
        success: res => {}
      });
    } else {
      // 没有允许定位权限
      wx.showToast({
        title: '您拒绝了定位权限,将无法使用XX功能',
        icon: 'none'
      });
    }
  }
});

wx.openSetting的success回调中可以判断用户是否已授权,并根据实际开发场景执行相关逻辑,这里为了简单演示,对于用户已授权的情况重新调用wx.getLocation进行定位;对于用户依然没有授权的情况,弹出一个Toast提示。
需要注意,官方文档中明确指出从2.3.0版本开始,当用户发生点击行为后才可以跳转打开设置页,不允许在用户无任何操作的情况下进行跳转,对于该限制,我们可以使用弹出一个模态框,当用户点击确定按钮时再跳转设置页面。最后附上定位的完整代码如下:

wx.getLocation({
  success: res => {
    console.log(res);
  },
  fail: e => {
    console.log(e);
    // 判断用户是否拒绝了授权
    wx.getSetting({
      success: res => {
        if (typeof(res.authSetting['scope.userLocation']) != 'undefined' && !res.authSetting['scope.userLocation']) {
          // 用户拒绝了授权
          wx.showModal({
            title: '提示',
            content: '您拒绝了定位权限,将无法使用XX功能',
            success: res => {
              if (res.confirm) {
                // 跳转设置页面
                wx.openSetting({
                  success: res => {
                    if (res.authSetting['scope.userLocation']) {
                      // 授权成功,重新定位
                      wx.getLocation({
                        success: res => {}
                      });
                    } else {
                      // 没有允许定位权限
                      wx.showToast({
                        title: '您拒绝了定位权限,将无法使用XX功能',
                        icon: 'none'
                      });
                    }
                  }
                });
              }
            }
          });
        }
      }
    });
});

这里使用的是第一种方式判断用户是否拒绝了授权,使用错误信息来判断也是一样的,就不展示了。
最后展示一下运行效果:

总结

由于微信小程序只会向用户申请一次授权,之后的授权记录会一直保留,并且用户拒绝授权会导致相关API调用失败,因此我们需要考虑用户拒绝授权的情况。本文以获取位置信息的API为例,介绍了微信小程序中如何处理这种情况,对于其他权限来说逻辑也是类似的,主要包括两个步骤:
1.判断用户是否拒绝了授权。
2.对于用户拒绝授权的情况,跳转小程序设置页面引导用户手动授权。
具体的处理方式还是要考虑实际项目的功能,如果该权限涉及到的功能不是必需的(比如定位获取到的位置信息可以为空),那么当然可以不用做这些处理,我这里只是提供了一种思路,大体的判断逻辑是不会变的。
此外如果我有什么分析得不对的地方欢迎大家提出指正。

参考文章

微信小程序官方文档——授权

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,565评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,021评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,003评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,015评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,020评论 5 370
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,856评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,178评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,824评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,264评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,788评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,913评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,535评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,130评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,102评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,334评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,298评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,622评论 2 343

推荐阅读更多精彩内容

  • 大家好,我是IT修真院深圳分院第07期学员,一枚正直善良的web程序员。 今天给大家分享一下,修真院官网 JS-1...
    SIRengar阅读 1,171评论 0 0
  • 1.授权相关概念 (1)为什么要授权部分接口需要经过用户授权同意才能调用。我们把这些接口按使用范围分成多个 sco...
    嘻洋洋阅读 2,887评论 0 1
  • 据说,那个时候搬过来,厂房也只有一跨,地方虽然比先前的地下室大了不少,但是这样一来地方就显得非常空旷,因为做产品设...
    骑驴书生阅读 532评论 0 51
  • 今天是2017年的第二天,新的一年,新的开始,也注定会有新的收获。 我和你们一样,在做圈子的同时也在加入别人的圈子...
    潜龙会阅读 222评论 0 0
  • 感恩今天,感恩生命中的一切都来的轻松愉快并充满荣耀。我是金钱,我是力量,我是觉知,我是创造,我是喜悦,我是丰盛,我...
    Demi瑶瑶阅读 253评论 0 0