微信小程序摄像头权限状态同步获取判断前端显示以及多次授权弹窗的问题

微信小程序二维码或者条形码扫码等功能开发中,总会遇到用户摄像头权限开启隐藏的问题,这里通常需要获取摄像头权限及时更新前端显示,最主要是用户授权提示弹窗操作后及时获取状态

问题一:用户未授权时,进入页面出现两次授权弹窗

原因是因为camera组件自动触发了一次授权,然后代码又写了wx.authorize发起授权。这里可以采取用wx:if来控制camera的加载,后续的关闭摄像头也可以用到

问题二:授权弹窗用户操作后,无法及时监听到最新状态

utils/cameraPermission.js
// utils/cameraPermission.js

/**
 * 检查摄像头权限
 * @returns {Promise<boolean>} 返回一个 Promise,表示是否已授权
 */
function checkCameraPermission() {
  return new Promise((resolve, reject) => {
    wx.getSetting({
      success(res) {
        resolve(!!res.authSetting['scope.camera']);
      },
      fail(err) {
        reject(err);
      }
    });
  });
}

/**
 * 请求摄像头权限
 * @returns {Promise<boolean>} 返回一个 Promise,表示是否授权成功
 */
function requestCameraPermission() {
  return new Promise((resolve, reject) => {
    wx.authorize({
      scope: 'scope.camera',
      success() {
        resolve(true);
      },
      fail() {
        resolve(false);
      }
    });
  });
}

/**
 * 检查并请求摄像头权限
 * @returns {Promise<boolean>} 返回一个 Promise,表示是否已授权
 */
function checkAndRequestCameraPermission() {
  return new Promise(async (resolve, reject) => {
    try {
      let isAuthorized = await checkCameraPermission();
      if (isAuthorized) {
        resolve(true);
        return;
      }

      // 用户未授权,尝试请求授权
      isAuthorized = await requestCameraPermission();
      if (isAuthorized) {
        resolve(true);
        return;
      }

      // 用户拒绝授权,提示用户前往设置
      wx.showModal({
        title: '提示',
        content: '您未授权摄像头权限,是否前往设置?',
        success(modalRes) {
          if (modalRes.confirm) {
            wx.openSetting({
              success(settingData) {
                resolve(!!settingData.authSetting['scope.camera']);
              },
              fail(err) {
                reject(err);
              }
            });
          } else {
            // 用户拒绝前往设置,不再提示
            resolve(false);
          }
        }
      });
    } catch (err) {
      reject(err);
    }
  });
}

module.exports = {
  checkAndRequestCameraPermission
};
index.html
<camera wx:if="{{cameraShow}}" mode="scanCode" frame-size='large' flash="{{ cameraFlash }}" class="scan-view" bindscancode='scancode'>
  <view >
    <t-icon name="close" class="arrowBack" size="60rpx" />
    <span>{{title}}</span>
    <span style="width: 100rpx;"></span>
  </view>
  <view class="cameratips" wx:if="{{!hasCameraPermission}}">您未开启摄像头权限</view>
</camera>
index.js
const animation = wx.createAnimation({}); // 创建移动动画对象
// const innerAudioContext = wx.createInnerAudioContext() // 提示音
// innerAudioContext.src = ' mp3 文件网络地址  '
const { checkAndRequestCameraPermission } = require('../../../utils/cameraPermission'); 
 
Page({
 
  /**
   * 页面的初始数据
   */
  data: {
    canScan: true,
    deviceId:'',
    hasCameraPermission: false,
    cameraShow:false,
    cameraContext: null
  },
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    this.checkAndRequestPermission();
    // 监听应用显示事件
    this.appShowHandler = () => {
      this.checkAndRequestPermission();
    };
    wx.onAppShow(this.appShowHandler);
  },
 
  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {
 
  },
 
  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {
    
    
  },
 
  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {
 
  },
 
  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {
    // 页面卸载时移除事件监听
    if (this.appShowHandler) {
      wx.offAppShow(this.appShowHandler);
    }
    // 确保在页面卸载时关闭摄像头
    this.stopUsingCamera();
  },
  async checkAndRequestPermission() {
    try {
      const isAuthorized = await checkAndRequestCameraPermission();
      this.setData({ hasCameraPermission: isAuthorized,cameraShow:true });
      if (isAuthorized) {
        this.startUsingCamera();
      } else {
        this.stopUsingCamera();
      }
    } catch (err) {
      console.error('检查和请求摄像头权限时出错:', err);
    }
  },

  startUsingCamera() {
    // 创建摄像头上下文
    const cameraContext = wx.createCameraContext();
    this.setData({ cameraContext }, () => {
      // 确保在数据更新后再打开摄像头
      this.openCamera(cameraContext);
    });
  },

  openCamera(cameraContext) {
    // 这里可以添加具体的打开摄像头逻辑
    console.log('尝试打开摄像头');
    // 示例:拍照
    cameraContext.takePhoto({
      quality: 'high',
      success: (res) => {
        console.log('拍照成功', res.tempImagePath);
      },
      fail: (err) => {
        console.error('拍照失败', err);
      }
    });
  },

  stopUsingCamera() {
    this.setData({ cameraShow:false })
    // 停止使用摄像头的逻辑
    console.log('停止使用摄像头');
    // 销毁摄像头上下文
    if (this.data.cameraContext) {
      this.data.cameraContext = null;
      this.setData({ cameraShow:true })
    }
  },
  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function () {
 
  },
 
  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {
 
  },
 
  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {
 
  },
  // 添加扫描动画
  startAnimation() {
    let down = true
    setInterval(() => {
      if (down) {
        animation.translateY(100).step({ duration: 3000 })
      } else {
        animation.translateY(0).step({ duration: 3000 })
      }
      down = !down
      this.setData({ animation: animation.export() })
    }, 3000)
  },
 
  scancode(event) {
    // if (!this.data.canScan) {
    //   return; // 如果不能扫码,直接返回
    // }
    // this.setData({ canScan: false }); // 设置为不能扫码
    // wx.vibrateShort() // 触发手机振动
    // innerAudioContext.play() // 提示音
    const { result } = event.detail // 获取校验扫描结果
    this.setData({
      deviceId:result
    })
  },
  
  
  
})

解释

  • checkCameraPermission:

    检查用户是否已经授权摄像头权限。

  • requestCameraPermission:

    请求用户授权摄像头权限,不显示自定义弹窗。如果用户授权成功,返回 true;否则返回 false。

  • checkAndRequestCameraPermission:

    首先检查用户是否已经授权摄像头权限。
    如果用户已授权,直接返回授权状态。
    如果用户未授权,尝试请求授权(此时微信会自动弹出系统授权弹窗)。
    如果用户拒绝授权,提示用户前往设置页面手动开启权限。
    如果用户拒绝前往设置,不再提示。

  • onLoad:

    在页面加载时检查并请求摄像头权限。
    监听应用显示事件 (wx.onAppShow),在应用显示时重新检查权限。

  • onUnload:

    在页面卸载时移除应用显示事件的监听。
    确保在页面卸载时关闭摄像头,调用 stopUsingCamera 方法。

  • checkAndRequestPermission:

    检查并请求摄像头权限。
    根据权限状态更新 isCameraAuthorized 数据。
    如果已授权,调用 startUsingCamera 方法;否则调用 stopUsingCamera 方法。

  • startUsingCamera:

    创建摄像头上下文。
    更新 cameraContext 数据,并在数据更新完成后调用 openCamera 方法尝试打开摄像头。

  • openCamera:

    尝试打开摄像头并执行具体操作(例如拍照)。
    处理打开摄像头的成功和失败情况。

  • stopUsingCamera:

    停止使用摄像头的逻辑。
    销毁摄像头上下文,确保摄像头资源被释放。
    可以在这里添加其他关闭摄像头的操作。

关键点

  • 权限检查: 在每次尝试打开摄像头之前,确保已经检查并获取了最新的权限状态。
  • 实时监听: 使用 wx.onAppShow监听应用显示事件,在应用显示时重新检查权限。
  • 关闭摄像头: 在 stopUsingCamera方法中销毁摄像头上下文,确保摄像头资源被释放。
  • 确保数据更新: 在 startUsingCamera 方法中,确保在cameraContext 数据更新完成后才调用 openCamera 方法。
  • 错误处理:在打开摄像头失败时,捕获并处理错误,以便进行调试和修复。

通过这种方式,确保在用户重新授权后能够正确打开摄像头,并且在权限状态发生变化时能够及时响应。同时,确保在用户拒绝授权或不再需要使用摄像头时真正关闭摄像头,释放相关资源。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

niech_cn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值