最近在研究运动软件Keep,就是那个自律给我自由的Keep。主要方法是使用Charles来抓包,然后查看接口。由于Charles是一款Mac的应用,所以Windows系统,可能不能实践了。另外安卓手机限制不能抓包HTTPS的协议,所以也不能实践了。
现在分享一下我的研究成果,本文可能触及到Keep软件的一些特殊操作,大家谨慎使用,本文仅供学习和交流使用,如果侵犯到Keep的相关利益,请联系我。
Keep是典型的混合式开发,也就是前端H5 + 后端 + 移动端(安卓和iOS),大多界面都是使用了前端技术开发的,主要前端框架是基于VUE来做的。
主要域名
后端服务域名:https://api.gotokeep.com
主站H5:https://show.gotokeep.com
活动等H5:https://m.gotokeep.com
静态资源CDN:https://static1.keepcdn.com
监控:https://apm.gotokeep.com
智能设备:https://kit.gotokeep.com
userAgent
userAgent是混合开发中,H5用来识别APP内部与外部的重要依据。前端可以通过JavaScript代码window.navigator.userAgent来获取,Keep的userAgent`如下:
Mozilla/5.0 (iPhone; CPU iPhone OS 13_5_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148;Keep/6.43.0 (iPhone; iOS 13.5.1; Scale/2.00);Keep/6.43.0 (iPhone; iOS 13.5.1; Scale/2.00)
当然不同系统是不一样的,其中最重要的是最后Keep/版本号(其他信息)这一段,至于为什么要写2遍,我也不清楚,难道客户端植入的时候多写了一遍?
调试页面
Keep线上的页面都是线上环境,调试线上环境的其实也没有多大的意义。由于我们拿不到Keep的源代码,所以只能通过线上代码简单地看看Keep页面的结构。
Keep使用了vue + vue-router + vuex这样的框架组合,它的页面链接的最后一级是用户的userId,我们以“我的等级”页面为例,如:https://show.gotokeep.com/experience/grades/xxxxxxxxxxxxxxxxxxxxxxxx?kg=16其中xxxxxxxxxxxxxxxxxxxxxxxx就是userId,由于用户的userId是隐私数据,所以我就那x来代替了(下面所有有userId的地方,我都会用xxxxxxxxxxxxxxxxxxxxxxxx来代替)。
浏览器直接打开这个页面,发现报错了,仔细一看,你会发现是接口https://api.gotokeep.com/diamond/v1/users/xxxxxxxxxxxxxxxxxxxxxxxx/privilegeWall/levels返回了401,接口401说明没有授权。为了让页面实现在Keep中同样的效果,可以做下面的几步:
让H5页面识别浏览器为Keep站内。
要识别站内就是使用上面的
userAgent,打开开发者工具,然后选择Network conditions面板,去掉Select automatically的勾选,然后把上面的userAgent粘贴到下面的输入框中,如下,然后刷新一下userAgent就生效了。
获取cookie。
Keep接口认证是基于
JWT来实现的。我们使用Charles来查看任一接口的cookie,会发现有一个authorization的字段,这个就是JWT的关键,如下:
设置cookie。
为了页面能正常运行,我们把所有的
cookie信息,都设置进去。打开浏览器的开发者工具,然后依次把cookie粘贴进去,如下:
此时刷新页面,可以看到页面已经可以正常运行了,如下:

客户端事件
客户端事件是H5和客户端(这里只有移动端)交互的指令,其实就是一个特定协议的字符串,前端使用location.href = 客户端事件字符串来执行客户端事件,在Keep中为了方便调试,也可以扫码来执行这些事件。举个例子,打开webview的事件是keep://webview/后面跟着encode的URI就可以实现跳转页面了,比如要使用Keep来跳转本博客,就可以如下:keep://webview/https%3a%2f%2fwww.kai666666.com%2f,你可以使用这个工具来encode,把刚才的事件,转换为二维码,如下:

现在打开Keep扫一扫,上面的二维码,你就可以用Keep进入本博客网站了。要把字符串转换为二维码可以使用草料二维码。
在https://api.gotokeep.com/config/v2/basic?refresh=true接口中定义了更多的事件:
| 描述 | 事件 |
|---|---|
| 精选 | keep://discover_web |
| 训练 | keep://discover_course |
| 饮食 | keep://discover_food |
| 商城 | keep://discover_store |
| 精选 | keep://discovery/explore |
| 训练 | keep://discovery/course |
| 攻略 | keep://discovery/guide |
| 饮食 | keep://discovery/diet |
| 商城 | keep://discovery/product |
| 推荐 | keep://hottabs/hot |
| 热门视频 | keep://hottabs/video |
| 运动时刻 | keep://hottabs/story |
| training_训练课程 | keep://discover_course/ |
| activity_热门活动 | keep://hot_activities |
| hashtag_话题讨论 | keep://hashtags_index |
| group_小组推荐 | keep://groups_index/ |
| kol_达人推荐 | keep://recommend_keepers/ |
| article_精选文章 | keep://selections |
| 热门 | keep://timeline/hot |
| 关注 | keep://timeline/follow |
| 逛逛 | keep://timeline/wander |
| 训练 | keep://homepage/content?tabId=ZnVsbENvbnRlbnQ= |
| 跑步 | keep://homepage/running?tabId=cnVubmluZw== |
| 瑜伽 | keep://homepage/yoga?tabId=eW9nYQ== |
| 行走 | keep://homepage/hiking?tabId=aGlraW5n |
| 骑行 | keep://homepage/cycling?tabId=Y3ljbGluZw== |
| Kit | keep://homepage/keloton?tabId=a2Vsb3Rvbg== |
| 数据中心 | keep://datacenter?type=all&period=day |
| 跑步历史记录 | keep://datacenter?type=running&period=day |
| 每周目标 | keep://weeklypurpose |
| 身体档案 | keep://bodydata |
| 运动能力 | keep://physical_test_list |
| 运动概况 | keep://physical_summary |
| 运动日记 | https://show.gotokeep.com/usersfulldiary |
| 步数记录 | keep://steps_dashboard |
| 连接应用和设备 | keep://oauth/list |
| 我的收藏 | keep://my_favorites |
| 我的活动 | keep://activities |
| 训练营历史 | keep://bootcamp/history |
| 我的路线 | keep://my_running_routes |
| 我的运动小队 | https://show.gotokeep.com/outdoor/groups/list |
| 我的最佳成绩 | keep://running/best_records |
| 我的 Class | keep://classes/mine |
| 购物车 | keep://shopping_cart |
| 我的钱包 | https://show.gotokeep.com/wallet |
| 优惠券 | keep://store_coupons |
| 购买记录 | keep://purchase_history |
| Keepland 课程 | https://keepland.gotokeep.com/my_course?pulldownrefresh=true |
从上面可以看到很多https://show.gotokeep.com开头的地址用Keep扫码也是可以直接进入的,但是我们自己的https网站却不能,可见Keep对自己的白名单内的域名做了特殊处理(相当于其他页面使用了keep://webview/事件)。
小应用
Keep并没有提供一种查看自己跑了多少个全马,或者跑了多少个半马这样的功能。现在我们写个脚本把自己的跑步数据存入我们自己的数据库中,并通过SQL查询出我们跑了多少个半马。
这里假设你已经安装了MySQL,并且已经建立了一个名叫keep_running的数据库。
建表脚本如下:
1 | DROP TABLE IF EXISTS running_data; |
要得到自己的跑步数据,可以调用https://api.gotokeep.com/pd/v3/stats/detail接口来获取,由于浏览器端会有跨域的问题,所以我们就直接跑一个node脚本就行了。
这里需要用到额外的两个库,一个是axios,用来发送http请求的;另一个库就是mysql,用来把数据存到数据库的。大家自己运行npm install一下。
脚本大致如下:
1 | const axios = require('axios').default |
注意上面headers处,需要换成自己数据的键值对形式,在Charles中获取方式如下:

最后你就可以通过SQL语句查询数据了:
1 | # 全马 |
通过数据查询可以看出我自己跑了10个半马了😀。
