小程序获取微信运动步数并集成echarts报表显示

短命女 2023-06-25 04:51 72阅读 0赞

需求

现在运动计步非常的火,大家常用的计步工具一般有keep、咕咚、微信运动和其他移动设备等,本文是基于微信小程序获取用户的微信运动数据并可视化呈现出来。

先看一下最终实现效果:
在这里插入图片描述

微信运动规则

在开发之前需要了解一下微信运动信息的使用规则,这样会规避掉很多问题。
1、微信运动数据必须在微信生态内获取,即小程序、公众号等,且需要用户进行授权。
2、用户主动进入小程序时可以获取到最近30天的运动数据,且一次性获取全部,不能获取指定时间段内的运动数据。
3、目前只能获取到运动“步数”,其他的获取不到(例如:卡路里、公里数、运动轨迹等)。

实现步骤

如果要实现上图示例中的效果需要完成一下几个步骤:

  1. 1、调用小程序APIwx.login获取codesessionKey
  2. 2、调用小程序APIwx.getWeRunData 获取微信运动数据(加密);
  3. 3、调用后端API将运动数据进行解密(Java);
  4. 4、小程序集成echarts.js 实现线状图展示;

小程序代码(原生)

第一步:配置页面

在app.json 文件pages内增加WeRunData配置将会自动创建WeRunData.js、WeRunData.json、WeRunData.wxml和WeRunData.wxss 四个文件。

  1. "pages":[
  2. "pages/WeRunData/WeRunData"
  3. ],
第二步:获取微信授权
  1. var app = getApp()
  2. var userInfo = null;
  3. Page({
  4. globalData: {
  5. appid: 'wx4167******16a0a1',//appid需自己提供,此处的appid我随机编写
  6. secret: '5498fcab20f********df26bf854ba89',//secret需自己提供,此处的secret我随机编写
  7. },
  8. data: {
  9. userInfo: {},
  10. hasUserInfo: false,
  11. canIUse: wx.canIUse('button.open-type.getUserInfo'),
  12. encryptedData:null,
  13. sessionkey:null,
  14. iv:null
  15. },
  16. onLoad: function () {
  17. var that = this;
  18. if (app.globalData.userInfo) {
  19. this.setData({
  20. userInfo: app.globalData.userInfo,
  21. hasUserInfo: true
  22. })
  23. } else if (this.data.canIUse) {
  24. // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回
  25. // 所以此处加入 callback 以防止这种情况
  26. app.userInfoReadyCallback = res => {
  27. this.setData({
  28. userInfo: res.userInfo,
  29. hasUserInfo: true
  30. })
  31. }
  32. } else {
  33. // 在没有 open-type=getUserInfo 版本的兼容处理
  34. wx.getUserInfo({
  35. success: res => {
  36. app.globalData.userInfo = res.userInfo
  37. this.setData({
  38. userInfo: res.userInfo,
  39. hasUserInfo: true
  40. })
  41. }
  42. })
  43. }
  44. //登录凭证校验。通过 wx.login() 接口获得临时登录凭证 code 后传到开发者服务器调用此接口完成登录流程。
  45. wx.login({
  46. success: function (res) {
  47. if (res.code) {
  48. console.log("res.code:" + res.code);
  49. var d = that.globalData;//这里存储了appid、secret、token串
  50. var l = 'https://api.weixin.qq.com/sns/jscode2session?appid=' + d.appid + '&secret=' + d.secret + '&js_code=' + res.code + '&grant_type=authorization_code';
  51. wx.request({
  52. url: l,
  53. data: {},
  54. method: 'GET',
  55. success: function (res) {
  56. var obj = {};
  57. obj.openid = res.data.openid;
  58. console.log("openid:" + obj.openid);
  59. console.log("session_key:" + res.data.session_key);
  60. obj.expires_in = Date.now() + res.data.expires_in;
  61. that.setData({
  62. sessionkey: res.data.session_key,
  63. })
  64. wx.setStorageSync('user', obj);//存储openid
  65. wx.getWeRunData({
  66. success(res) {
  67. // 拿 encryptedData 到开发者后台解密开放数据
  68. const encryptedData = res.encryptedData
  69. console.log("encryptedData:" + encryptedData)
  70. // 或拿 cloudID 通过云调用直接获取开放数据
  71. const cloudID = res.cloudID
  72. console.log("cloudID:" + cloudID)
  73. console.log("iv:" + res.iv)
  74. // 解密运动数据
  75. that.setData({
  76. encryptedData: res.encryptedData,
  77. iv: res.iv
  78. })
  79. // 调用第三步去解密
  80. that.getEncryptedData();
  81. }
  82. })
  83. }
  84. });
  85. } else {
  86. console.log('获取用户登录态失败!' + res.errMsg)
  87. }
  88. }
  89. });
  90. },
  91. getUserInfo: function (e) {
  92. console.log(e)
  93. app.globalData.userInfo = e.detail.userInfo
  94. this.setData({
  95. userInfo: e.detail.userInfo,
  96. hasUserInfo: true
  97. })
  98. }
  99. })
第三步:解密运动数据

WeRunData.js 解密

  1. getEncryptedData: function () {
  2. var that = this;
  3. wx.request({
  4. url: 'http://127.0.0.1:8080/getEncryptedData', // 这里需要去请求后端代码进行解密,示例中使用Java实现。
  5. method: "POST",
  6. data: {
  7. encryptedData: this.data.encryptedData,
  8. sessionkey: this.data.sessionkey,
  9. iv: this.data.iv
  10. },
  11. header: {
  12. "Content-Type": "application/json"
  13. },
  14. success: function (res) {
  15. console.log("解密后的数据为:", res);
  16. if (res.statusCode == 200) {
  17. let stepInfoList = res.data.stepInfoList;
  18. let data = [];
  19. let categories = [];
  20. for (let i = 0; i < stepInfoList.length; i++) {
  21. categories.push(stepInfoList[i].stepTime);
  22. data.push(stepInfoList[i].step);
  23. }
  24. chartData.main.categories = categories;
  25. chartData.main.data = data;
  26. // 调用第四步 可视化加载
  27. that.stepChartLine();
  28. }
  29. }
  30. })
  31. },
第四步:集成echarts.js 运动数据可视化

集成步骤可以参考Echarts官方步骤:https://github.com/ecomfe/echarts-for-weixin
WeRunData.js 渲染图表

  1. import * as echarts from '../../ec-canvas/echarts';
  2. var chartData = {
  3. main: {
  4. data: [], // 运动步数集合
  5. categories: [] // 运动日期集合
  6. }
  7. };
  8. //初始化图表
  9. init_echarts: function () {
  10. this.echartsComponnet.init((canvas, width, height) => {
  11. // 初始化图表
  12. const Chart = echarts.init(canvas, null, {
  13. width: width,
  14. height: height
  15. });
  16. Chart.setOption(this.getOption());
  17. // 注意这里一定要返回 chart 实例,否则会影响事件处理等
  18. return Chart;
  19. });
  20. },
  21. // 获取数据
  22. getOption: function () {
  23. var that = this
  24. var legendList = []
  25. var option = {
  26. title: {
  27. left: 'center'
  28. },
  29. color: ["#37A2DA"],
  30. grid: {
  31. containLabel: true
  32. },
  33. tooltip: {
  34. show: true,
  35. trigger: 'axis'
  36. },
  37. xAxis: {
  38. type: 'category',
  39. boundaryGap: false,
  40. data: chartData.main.categories
  41. },
  42. yAxis: {
  43. x: 'center',
  44. type: 'value',
  45. splitLine: {
  46. lineStyle: {
  47. type: 'dashed'
  48. }
  49. }
  50. },
  51. series: [{
  52. type: 'line',
  53. smooth: true,
  54. data: chartData.main.data
  55. }]
  56. };
  57. return option
  58. }
第五步:页面布局

WeRunData.wxml

  1. <view class="userinfo">
  2. <button wx:if="{
  3. {!hasUserInfo && canIUse}}" open-type="getUserInfo" bindgetuserinfo="getUserInfo" class="userinfo-btn"> 点击微信授权 </button>
  4. <block wx:else>
  5. <image bindtap="bindViewTap" class="userinfo-avatar" src="{
  6. {userInfo.avatarUrl}}" background-size="cover"></image>
  7. <text class="userinfo-nickname">{
  8. {userInfo.nickName}}</text>
  9. </block>
  10. </view>
  11. <view class="container">
  12. <ec-canvas id="mychart-dom-line" canvas-id="mychart-line" ec="{
  13. { ec }}"></ec-canvas>
  14. </view>

WeRunData.wxss

  1. .userinfo {
  2. display: flex;
  3. flex-direction: column;
  4. align-items: center;
  5. background: #f0145a;
  6. width: 100%;
  7. height: 300rpx;
  8. }
  9. .userinfo-btn{
  10. margin-top: 50rpx;
  11. background: none !important;
  12. color: #fff !important;
  13. font-size: 40rpx;
  14. }
  15. .userinfo-avatar {
  16. width: 108rpx;
  17. height: 108rpx;
  18. margin: 40rpx;
  19. border-radius: 50%;
  20. }
  21. .userinfo-nickname {
  22. color: #fff;
  23. }
  24. ec-canvas {
  25. width: 100%;
  26. height: 70%;
  27. position: absolute;
  28. margin-top: 300rpx;
  29. top: 0;
  30. bottom: 0;
  31. left: 0;
  32. right: 0;
  33. }

后端解密代码(Java)

EncryptedDataController.java

  1. // 解密微信运动数据
  2. @ApiImplicitParam(name = "map",value = "{\"encryptedData\":\"001\",\"sessionkey\":\"2123\",\"iv\":\"111\"}" )
  3. @PostMapping(value = "/getEncryptedData", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
  4. public WxChartStepInfoDTO getEncryptedData(@RequestBody Map<String,String> map) {
  5. String encryptedData = map.get("encryptedData");
  6. String sessionkey = map.get("sessionkey");
  7. String iv = map.get("iv");
  8. // 被加密的数据
  9. byte[] dataByte = Base64.decode(encryptedData);
  10. // 加密秘钥
  11. byte[] keyByte = Base64.decode(sessionkey);
  12. // 偏移量
  13. byte[] ivByte = Base64.decode(iv);
  14. try {
  15. // 如果密钥不足16位,那么就补足
  16. int base = 16;
  17. if (keyByte.length % base != 0) {
  18. int groups = keyByte.length / base + (keyByte.length % base != 0 ? 1 : 0);
  19. byte[] temp = new byte[groups * base];
  20. Arrays.fill(temp, (byte) 0);
  21. System.arraycopy(keyByte, 0, temp, 0, keyByte.length);
  22. keyByte = temp;
  23. }
  24. // 初始化
  25. Security.addProvider(new BouncyCastleProvider());
  26. Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
  27. SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");
  28. AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");
  29. parameters.init(new IvParameterSpec(ivByte));
  30. cipher.init(Cipher.DECRYPT_MODE, spec, parameters);// 初始化
  31. byte[] resultByte = cipher.doFinal(dataByte);
  32. if (null != resultByte && resultByte.length > 0) {
  33. String result = new String(resultByte, "UTF-8");
  34. System.out.println("result:" + result);
  35. Gson gson = new Gson();
  36. WxChartStepInfoDTO wxChartStepInfoDTO = gson.fromJson(result,WxChartStepInfoDTO.class);
  37. return wxChartStepInfoDTO;
  38. }
  39. } catch (NoSuchAlgorithmException e) {
  40. e.printStackTrace();
  41. } catch (NoSuchPaddingException e) {
  42. e.printStackTrace();
  43. } catch (InvalidParameterSpecException e) {
  44. e.printStackTrace();
  45. } catch (IllegalBlockSizeException e) {
  46. e.printStackTrace();
  47. } catch (BadPaddingException e) {
  48. e.printStackTrace();
  49. } catch (UnsupportedEncodingException e) {
  50. e.printStackTrace();
  51. } catch (InvalidKeyException e) {
  52. e.printStackTrace();
  53. } catch (InvalidAlgorithmParameterException e) {
  54. e.printStackTrace();
  55. } catch (NoSuchProviderException e) {
  56. e.printStackTrace();
  57. }
  58. return null;
  59. }

WxChartStepInfoDTO.java

  1. @NoArgsConstructor
  2. @Data
  3. @ApiModel(value = "微信运动实体")
  4. public class WxChartStepInfoDTO implements Serializable{
  5. private static final long serialVersionUID = -4526066242748484991L;
  6. private List<StepListBean> stepInfoList;
  7. private WatermarkBean watermark;
  8. @NoArgsConstructor
  9. @Data
  10. public static class StepListBean implements Serializable {
  11. Long timestamp; // 运动日期
  12. Integer step; // 运动步数
  13. @JsonFormat(pattern = "MM-dd")
  14. Date stepTime; // 运动日期(格式化为:yyyy-MM-dd HH:mm:ss)
  15. public Date getStepTime() {
  16. return StringUtil.getSecondToDate(this.timestamp,"yyyy-MM-dd HH:mm:ss");
  17. }
  18. }
  19. @NoArgsConstructor
  20. @Data
  21. public static class WatermarkBean implements Serializable {
  22. @ApiModelProperty(value = "同步微信运动时间")
  23. private Long timestamp;
  24. @ApiModelProperty(value = "appid",required = true)
  25. private String appid;
  26. @ApiModelProperty(value = "格式化运动时间")
  27. @JsonFormat(pattern = "MM-dd")
  28. Date time; // 运动日期(格式化为:yyyy-MM-dd HH:mm:ss)
  29. public Date getTime() {
  30. return StringUtil.getSecondToDate(timestamp,"yyyy-MM-dd HH:mm:ss");
  31. }
  32. }
  33. }

最后

好了,小程序获取微信运动步数并集成echarts.js 可视化实现的具体做法就分享到这里了。如果大家有不明白的可以留言,需要源码的话也可以关注“IT实战联盟”公众号留下邮箱,小编有时间将会把源码发送给大家。

贡献者

  • IT实战联盟-Line

更多精彩内容可以关注“IT实战联盟”公号哦~~~

image

发表评论

表情:
评论列表 (有 0 条评论,72人围观)

还没有评论,来说两句吧...

相关阅读