UniApp + UniCloud 实现微信小程序静默登录

UniApp + UniCloud 实现微信小程序静默登录

目录

1. 项目准备

1.1 环境要求

  • HBuilderX 3.0+
  • 微信开发者工具
  • UniCloud 已开通
  • 微信小程序已注册

1.2 项目配置

  1. 在 manifest.json 中配置微信小程序 AppID:
{
  "mp-weixin": {
    "appid": "你的小程序AppID",
    "setting": {
      "urlCheck": false
    }
  }
}
  1. 在 pages.json 中添加登录页面:
{
  "pages": [
    {
      "path": "pages/index/index",
      "style": {
        "navigationBarTitleText": "首页"
      }
    }
  ]
}

2. UniCloud 配置

2.1 数据库集合创建

  1. 创建用户集合 uni-id-users
{
  "bsonType": "object",
  "required": ["_id"],
  "properties": {
    "_id": {
      "description": "ID,系统自动生成",
      "bsonType": "string"
    },
    "wx_openid": {
      "bsonType": "string",
      "description": "微信openid"
    },
    "wx_unionid": {
      "bsonType": "string",
      "description": "微信unionid"
    },
    "session_key": {
      "bsonType": "string",
      "description": "微信会话密钥"
    }
  }
}

2.2 uni-config-center 配置

uniCloud/cloudfunctions/common/uni-config-center/uni-id/config.json 中配置:

{
  "mp-weixin": {
    "appid": "你的小程序AppID",
    "appsecret": "你的小程序AppSecret"
  }
}

3. 前端实现

3.1 登录工具类

创建 utils/login.js

export default class LoginManager {
  static async silentLogin() {
    try {
      // 获取微信登录凭证
      const { code } = await uni.login({
        provider: 'weixin'
      });
      
      // 调用云函数登录
      const { result } = await uniCloud.callFunction({
        name: 'wx-silent-login',
        data: { code }
      });
      
      // 保存登录状态
      if (result.token) {
        uni.setStorageSync('uni_id_token', result.token);
        uni.setStorageSync('uni_id_token_expired', result.tokenExpired);
      }
      
      return result;
    } catch (e) {
      console.error('静默登录失败:', e);
      throw e;
    }
  }
  
  static async checkLoginState() {
    const token = uni.getStorageSync('uni_id_token');
    const tokenExpired = uni.getStorageSync('uni_id_token_expired');
    
    if (!token || !tokenExpired || tokenExpired < Date.now()) {
      return await this.silentLogin();
    }
    
    return { token, tokenExpired };
  }
}

3.2 页面使用

pages/index/index.vue 中:

<template>
  <view class="content">
    <text>{{userInfo ? '已登录' : '未登录'}}</text>
  </view>
</template>

<script>
import LoginManager from '@/utils/login.js'

export default {
  data() {
    return {
      userInfo: null
    }
  },
  onLoad() {
    this.checkLogin()
  },
  methods: {
    async checkLogin() {
      try {
        const loginState = await LoginManager.checkLoginState()
        if (loginState.userInfo) {
          this.userInfo = loginState.userInfo
        }
      } catch (e) {
        console.error(e)
      }
    }
  }
}
</script>

4. 云函数实现

4.1 创建云函数

创建 uniCloud/cloudfunctions/wx-silent-login/index.js

'use strict';
const uniID = require('uni-id-common')

exports.main = async function(event, context) {
  const { code } = event
  const uniIDIns = uniID.createInstance({ context })
  
  try {
    // 微信登录
    const wxLoginRes = await uniIDIns.loginByWeixin({
      code
    })
    
    // 如果是新用户,可以在这里进行额外处理
    if (wxLoginRes.type === 'register') {
      // 可以在这里添加用户初始化逻辑
    }
    
    return {
      errCode: 0,
      token: wxLoginRes.token,
      tokenExpired: wxLoginRes.tokenExpired,
      userInfo: wxLoginRes.userInfo
    }
  } catch (e) {
    return {
      errCode: e.errCode || -1,
      errMsg: e.errMsg || '登录失败'
    }
  }
}

5. 完整示例

5.1 登录流程

  1. 应用启动时检查登录状态
  2. 如果未登录或登录过期,进行静默登录
  3. 获取 code 并调用云函数
  4. 云函数处理登录逻辑并返回结果
  5. 前端保存登录状态

5.2 示例代码

App.vue 中:

<script>
import LoginManager from '@/utils/login.js'

export default {
  onLaunch: async function() {
    try {
      await LoginManager.checkLoginState()
    } catch (e) {
      console.error('登录失败:', e)
    }
  }
}
</script>

5.3 登录拦截器

创建 utils/request.js

const httpInterceptor = {
  invoke(options) {
    // 添加token
    const token = uni.getStorageSync('uni_id_token')
    if (token) {
      options.header = {
        ...options.header,
        'x-token': token
      }
    }
    
    // 请求拦截
    return options
  },
  success(response) {
    // 如果token过期,尝试重新登录
    if (response.data.errCode === 'TOKEN_INVALID') {
      LoginManager.silentLogin()
    }
    return response
  }
}

uni.addInterceptor('request', httpInterceptor)
uni.addInterceptor('uploadFile', httpInterceptor)

注意事项

  1. 确保微信小程序的 AppID 和 AppSecret 配置正确
  2. 处理好登录失败的情况
  3. 注意 token 的有效期管理
  4. 考虑数据安全性,避免敏感信息泄露
  5. 建议添加请求重试机制

参考资源

<think>嗯,用户让我介绍一下uniapp的面试难点。首先,我需要回忆一下自己对uniapp的了解。uniapp是一个使用Vue.js开发跨平台应用的框架,支持多种小程序、H5、App等。面试难点可能涉及框架原理、跨平台兼容性、性能优化等方面。 首先,我应该考虑面试官可能关注的核心知识点。比如,uniapp的工作原理,如何实现跨平台?可能涉及条件编译、运行时处理不同平台的API差异。然后,性能优化是常见的问题,比如页面加载速度、渲染效率,还有如何处理不同平台的兼容性问题,比如样式适配、API差异。 接下来,需要想到常见的面试问题。比如,uniapp的生命周期和Vue的生命周期有什么不同?如何处理原生功能,比如调用摄像头或地理位置?还有,如何解决不同平台上的样式兼容问题,比如在微信小程序和H5中的CSS表现差异。 可能还要提到uniapp的优缺点,比如开发效率高但性能可能不如原生,如何在实际项目中权衡。还有状态管理,是否使用Vuex,如何处理跨页面的数据共享。 另外,打包和发布流程可能也是一个考察点,比如如何打包成不同平台的应用,需要注意哪些配置。还有调试技巧,比如使用真机调试时遇到的问题怎么解决。 还有,uniapp的组件和API的使用,比如内置组件如scroll-view、swiper,如何正确使用它们以及可能遇到的坑。比如在App端和微信小程序中的表现不一致,如何处理。 插件生态也是一个点,比如使用第三方插件时如何保证兼容性,或者如何开发自定义原生插件。 可能还需要提到项目经验,比如有没有实际开发过复杂的uniapp项目,遇到过哪些棘手的问题,如何解决的。比如多端适配中的具体案例,如何处理导航栏在不同平台的表现差异。 还有网络请求的封装,比如统一处理请求头、拦截器,不同平台的请求限制(如微信小程序需要配置合法域名)。 另外,更新机制,比如热更新和App升级的策略,如何在不发布新版本的情况下修复问题。 最后,可能需要了解一些最新的uniapp动态,比如是否支持Vue3,或者新的特性如uniCloud的使用。 总结一下,面试难点可能包括:跨平台原理、性能优化、兼容性处理、生命周期、原生功能集成、状态管理、打包发布、调试技巧、组件使用、插件开发、项目经验等。需要结合实际开发经验,给出具体的解决方案和案例,展示对uniapp的深入理解和问题解决能力。</think>以下是 Uniapp 面试常见难点及解析,按技术深度分层整理: --- ### 一、**核心原理层难点** 1. **跨平台实现原理** - 面试高频问题:_Uniapp 如何实现「一次开发多端运行」?_ - 关键点: - **编译时差异**:通过条件编译(`#ifdef` `#endif`)隔离平台特定代码 - **运行时差异**:通过 `uni` API 抹平平台 API 差异(如调用相机时自动区分微信 `wx.chooseImage` 和 H5 `input[type=file]`) - **渲染层差异**:小程序用 WebView 渲染,App 使用原生渲染或 WebView(可通过 `renderer:"native"` 强制原生) 2. **性能优化底层机制** - 必问题:_如何解决长列表滚动卡顿?_ - 高阶答案: ```javascript // 必须提及的优化方案 <scroll-view :scroll-y="true" @scrolltolower="loadMore"> <uni-list> <uni-list-item v-for="(item,index) in virtualList" :key="index"/> </uni-list> </scroll-view> ``` - 使用 **虚拟列表**(通过 `uni-list` 组件或手动计算可视区域) - 图片懒加载(`<image lazy-load>`) - 避免在 `v-for` 中使用复杂计算 --- ### 二、**多端兼容层难点** 1. **样式适配问题** - 典型问题:_如何解决 iOS 和 Android 的样式差异?_ - 解决方案: - 使用 `rpx` 单位实现响应式布局(1rpx=屏幕宽度/750) - 用 `uni.getSystemInfoSync()` 动态获取状态栏高度 - 通过 `manifest.json` 配置全局样式(如 `"app-plus": { "statusbar": {"style": "dark"} }`) 2. **原生能力调用** - 高频场景:_如何在 App实现扫码功能?_ - 标准流程: ```javascript // 必须区分平台 #ifdef APP-PLUS let barcode = uni.requireNativePlugin('uni-barcode') barcode.scan({}, (res) => { console.log(res.result) }) #endif ``` - 使用 `uni-app原生插件市场` 或自行封装原生模块 - 注意 iOS 需配置隐私权限描述(如 NSCameraUsageDescription) --- ### 三、**工程化难点** 1. **多环境打包配置** - 常见问题:_如何实现开发/测试/生产环境切换?_ - 专业方案: ```javascript // 在 vue.config.js 中配置环境变量 const isProduction = process.env.NODE_ENV === 'production' module.exports = { chainWebpack: config => { config.plugin('define').tap(args => { args[0]['process.env'].API_URL = isProduction ? '"https://api.prod.com"' : '"https://api.test.com"' return args }) } } ``` 2. **热更新方案** - 关键问题:_如何实现 App 不通过应用商店更新?_ - 标准答案: - 使用 `uni.downloadFile` + `uni.getUpdateManager` 实现静默更新 - 需配合服务端版本校验接口(返回 latestVersion、downloadUrl) - iOS 需注意 Apple 审核规则(不能热更新核心功能) --- ### 四、**高阶调试技巧** 1. **真机调试痛点** - 典型场景:_如何调试 App 端的原生插件?_ - 专业方法: - Android 使用 Chrome `chrome://inspect` 调试 WebView - iOS 使用 Safari 开发菜单调试 - 通过 `uni.report()` 上传日志到服务器 --- ### 五、**项目经验类问题** - **必问题**:_你在开发中遇到最难解决的兼容性问题是什么?_ - 满分回答结构: 1. 场景描述(如:_微信小程序 iOS 端 image 组件底部留白_) 2. 排查过程(使用 `uni.upx2px()` 发现单位转换问题) 3. 解决方案(添加 `vertical-align: bottom` 样式) 4. 经验总结(建立平台差异问题知识库) --- 以上内容需结合具体项目经验展开,建议准备 2-3 个深度技术实践案例,展现问题分析能力和技术钻研精神。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值