纯前端解析微信步数

在这里插入图片描述

在这里插入图片描述

编辑WXBizDataCrypt.js文件,在需要解析的页面使用

WXBizDataCrypt.js

var crypto = require('crypto')

function WXBizDataCrypt(appId, sessionKey) {
  this.appId = appId
  this.sessionKey = sessionKey
}

WXBizDataCrypt.prototype.decryptData = function (encryptedData, iv) {
  // base64 decode
  var sessionKey = new Buffer(this.sessionKey, 'base64')
  encryptedData = new Buffer(encryptedData, 'base64')
  iv = new Buffer(iv, 'base64')

  try {
     // 解密
    var decipher = crypto.createDecipheriv('aes-128-cbc', sessionKey, iv)
    // 设置自动 padding 为 true,删除填充补位
    decipher.setAutoPadding(true)
    var decoded = decipher.update(encryptedData, 'binary', 'utf8')
    decoded += decipher.final('utf8')
    
    decoded = JSON.parse(decoded)

  } catch (err) {
    // throw new Error('Illegal Buffer')
  }

  // if (decoded.watermark.appid !== this.appId) {
  //   throw new Error('Illegal Buffer')
  // }

  return decoded
}

module.exports = WXBizDataCrypt

index.vue

<template>
	<view style="background-color: aliceblue;height: 100vh;overflow: auto;padding-top: 8rpx;">
		<u-notice-bar text="由于微信仅提供用户近三十天的步数信息,请您每三十天内打开一次小程序。"></u-notice-bar>
		<view class="" style="text-align: center;font-size: 1.5rem;font-weight: bold;margin: 1rem 0;">
			微信步数
		</view>
		<uni-table ref="table" :loading="loading" stripe emptyText="暂无更多数据">
			<uni-tr>
				<uni-th width="100" align="center">时间</uni-th>
				<uni-th width="100" align="center">步数</uni-th>
			</uni-tr>
			<uni-tr v-for="(item, index) in arr" :key="index">
				<uni-td align="center">
					<view class="" style="display: flex;justify-content: center;"
						:style=" {color:date==item.timestamp?'#000':''}">
						<!-- clock -->
						<u-icon name="clock"></u-icon>
						<view class="" style="margin-left: 12rpx;">
							{{item.timestamp}}
						</view>
					</view>
				</uni-td>
				<uni-td align="center">
					<view style="display: flex;justify-content: center;"
						:style="{color:item.step>=8000?'#19be6b':date!=item.timestamp&&item.step<8000?'#909399':'#000' }">
						<image src="../../static/img/index/步数.svg" mode=""
							style="width: 36rpx;height: 36rpx;margin-right: 12rpx;"></image>
						<view>{{ item.step }}</view>
						<view class="" v-if="item.step>=8000">
							(已达标)
						</view>
					</view>

				</uni-td>
			</uni-tr>
		</uni-table>


		<u-toast ref="uToast"></u-toast>
		<u-popup :show="show1" mode="center" :round="10">
			<view style="bottom:0;width:600rpx">
				<view class="" style="padding: 48rpx;">
					<view class="" style="text-align: center;font-weight: bold;">
						提示
					</view>
					<view class="" style="color:red;line-height: 1.5rem;padding-top: 1rem;">
						由于微信仅提供用户近三十天的步数信息,请您每三十天内打开一次小程序。
					</view>
				</view>
<u-button :text="buttonText" :disabled="disabledButton" @click="offButton"></u-button>
			</view>
		</u-popup>
	</view>
</template>

<script>
	import WXBizDataCrypt from './WXBizDataCrypt.js'
	import {
		synchronizationStep,
		getUser,
		getUser_wx
	} from '../../api/index.js'
	export default {
		data() {
			return {
				title: 'Hello',
				appid: '',
				secret: '',
				session_key: '',
				arr: [],
				loading: true,
				show: false,
				show1: false,
				date: new Date().toISOString().slice(0, 10),
				userId: '',
				buttonText:'确定(5)',
				dateText:5,
				disabledButton:true,
				
				userIv:''
			}
		},
		onLoad() {
		},
		onShow() {
			this.login()
		},
		methods: {
			offButton() {
				this.show1 = false

				if (!this.userId) {
					this.$refs.uToast.show({
						type: 'default',
						message: "请进行身份绑定!",
					})
				}

			},

			login() {
				var that = this;
				const accountInfo = uni.getAccountInfoSync();
				this.appid = accountInfo.miniProgram.appId

				wx.login({
					success: function(res) {
						getUser_wx({
							code: res.code
						}).then(res => {
							var session_key = res.session_key;
							that.getStepInfo(that.appid, session_key);
							wx.setStorageSync('openid', res.openid)
						}).catch(err => {
							//隐藏加载框
							that.loading = false
						})

					}
				})


			},
			//获取encryptedData(没有解密的步数)和iv(加密算法的初始向量)
			getStepInfo: function(appid, session_key) {
				let that = this
				wx.getSetting({
					success: function(resSetting) {
						// 未开启微信运动授权   scope.userRunData
						// if (!res.authSetting['scope.werun']) {
						// 	wx.showModal({
						// 		title: '提示',
						// 		content: '获取微信运动步数,需要开启计步权限',
						// 		success: function(res) {
						// 			if (res.confirm) {
						// 				//跳转去设置
						// 				wx.openSetting({
						// 					success: function(res) {}
						// 				})
						// 			} else {
						// 				//不设置
						// 			}
						// 		}
						// 	})
						// } else {
						wx.getWeRunData({
							success: function(res) {
								var encryptedData = res.encryptedData;
								var iv = res.iv;
								this.userIv = res.iv
								console.log(this.userIv);
								var pc = new WXBizDataCrypt(appid, session_key);
								var data = pc.decryptData(encryptedData, iv)
								that.arr = data.stepInfoList.reverse().map(res => {
									return {
										timestamp: that.timeFun(res.timestamp),
										step: res.step
									}
								})
								wx.setStorageSync('bindList', data.stepInfoList.reverse())
								that.loading = false
								that.getUser()
							},
							fail: function(res) {
								if (res.err_code) {
									wx.showModal({
										title: '提示',
										content: '获取微信运动步数,需要开启计步权限',
										success: function(res) {
											if (res.confirm) {
												//跳转去设置
												wx.openSetting({
													success: function(
														res) {}
												})
											} else {
												uni.reLaunch({
													url: '/pages/index/index'
												})
											}
										},
										fail: function() {
											// uni.reLaunch({
											// 	url: '/pages/index/index'
											// })
										}
									})
								} else if (res.errMsg == 'getWeRunData:fail') {
									wx.showModal({
										title: '提示',
										content: '未开通微信运动,请关注“微信运动”公众号后重试',
										showCancel: false,
										confirmText: '知道了'
									})
								}

							}
						})
					}
					// }
				})
			},

			// 同步步数
			synchronization(arr) {
				synchronizationStep(wx.getStorageSync('openid'), arr).then()
			},
			// end

			// 身份获取
			getUser() {
				getUser({
					wxChatId: wx.getStorageSync('openid')
				}).then(res => {
					this.userId = res.data.userId
					// this.date = 5
					
					let aaa =  setInterval(()=>{
						this.buttonText = `确定(${this.dateText}`
						this.dateText--
						if(this.dateText < 0){
							clearInterval(aaa)
							this.disabledButton = false
							this.buttonText = `确定`
						}
					},1000)
					this.show1 = true
					if (res.data.userId) {
						this.arr.iv = this.userIv
						console.log(this.userIv);
						// this.synchronization(this.arr)
					} else {
						// this.show1 = true
					}

				})
			},
			// end


			timeFun(time) {
				const date = new Date(time * 1000);

				// 提取年、月、日
				const year = date.getFullYear();
				const month = ('0' + (date.getMonth() + 1)).slice(-2); // 月份从0开始计数,需要加1,并确保格式为两位数
				const day = ('0' + date.getDate()).slice(-2); // 确保格式为两位数

				return `${year}-${month}-${day}`;
			}

		}
	}
</script>

<style>
	.u-safe-bottom {
		padding-bottom: 0;
	}
	button{
		color: #3c9cff !important;
	}
</style>
### 微信API获取步数数据接口调用教程 #### 1. 前置条件 在调用微信步数 API 之前,开发者需完成以下准备工作: - **注册并认证服务号或小程序**:只有经过微信平台认证的服务号或小程序才能访问用户的运动步数。 - **配置权限范围**:确保应用已申请 `scope.w Walking` 权限[^1]。 #### 2. 接口概述 微信提供了两种方式来获取用户步数数据: - 对于 **微信小程序**,可以使用 `wx.getWeRunData()` 方法获取加密后的步数数据,并将其发送到服务器进行解密处理。 - 对于 **H5 页面**,可以通过微信 JS-SDK 提供的相关方法实现类似的步数读取功能[^2]。 #### 3. 小程序端操作流程 ##### a. 用户授权 在前端页面中调用 `wx.login()` 和 `wx.authorize()` 函数请求用户登录态以及运动数据的授权许可。如果用户尚未同意,则会弹窗提示其确认授予该权限: ```javascript wx.authorize({ scope: 'scope.walking', success () { console.log('用户已允许'); }, fail () { wx.showModal({ title: '警告', content: '您拒绝了授权,无法正常显示步数信息。', showCancel: false, }); } }); ``` ##### b. 获取 WeRun 加密数据包 一旦获得必要的权限之后,就可以执行下面这一步骤——调用 `wx.getWeRunData()` 接口取得包含用户每日行走记录在内的 JSON 字符串形式的数据对象。此字符串实际上是被 AES-CBC 方式加密过的原始资料: ```javascript wx.getWeRunData({ success (res) { const encryptedData = res.encryptedData; const iv = res.iv; // 发送至后台解析 sendToServer(encryptedData, iv); }, fail(err){ console.error("获取失败", err); } }) ``` ##### c. 后台解密逻辑 当从前端接收到上述两个参数后,在自己的业务系统内部利用官方文档里提到的方法对其进行还原即可得到最终想要的结果。具体来说就是先验证签名的有效性再做实际的内容提取工作[^3]。 以下是基于 Java 的一种可能实现方案片段: ```java import org.bouncycastle.jce.provider.BouncyCastleProvider; import javax.crypto.Cipher; import java.security.Security; ... public String decryptData(String sessionKeyStr, String encryptedDataStr, String ivStr)throws Exception{ Security.addProvider(new BouncyCastleProvider()); byte[] sessionKeyBytes = Base64.decodeBase64(sessionKeyStr); byte[] dataByte = Base64.decodeBase64(encryptedDataStr); byte[] ivByte = Base64.decodeBase64(ivStr); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding","BC"); SecretKeySpec spec=new SecretKeySpec(sessionKeyBytes,"AES"); IvParameterSpec ips= new IvParameterSpec(ivByte); cipher.init(Cipher.DECRYPT_MODE,spec,ips); return new String(cipher.doFinal(dataByte),"UTF-8"); } ``` #### 4. H5 端注意事项 对于嵌入网页中的场景而言,由于缺乏直接接触底层硬件的能力,所以更多时候还是依赖第三方插件或者 SDK 完成同样的目标。比如引入 JSSDK 并按照既定规则初始化环境变量之后便能够轻松达成目的。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值