Play商店页面改版后Jsoup无法获取应用最新版本号问题咨询
你碰到的空指针确实是Google Play商店前端重构导致的。旧版页面版本号固定在div.hAyfc:nth-child(4)节点下,近年Play商店多次调整DOM结构,不仅节点位置变了,很多节点class还是动态生成的混淆名,硬编码固定CSS选择器的爬取逻辑非常脆弱,页面任何小改动都会直接失效。
另外你原有代码里用的是2007年版Firefox 2.0的User-Agent,Play商店会对过旧UA返回适配老浏览器的精简页面,DOM结构和正常页面不一致,也会加剧匹配失败的问题。
方案1:正则匹配页面内容(稳定性远高于DOM选择,推荐)
不要依赖固定DOM节点,直接拿整个页面的HTML源码,用正则匹配Current Version字段对应的版本值,只要Google不在页面里改掉这个字段的文本标识,逻辑就不会失效。
直接替换你doInBackground方法里的解析逻辑即可:
@Override protected JSONObject doInBackground(String... params) { try { Document doc = Jsoup.connect("https://play.google.com/store/apps/details?id=" + context.getPackageName() + "&hl=en") .timeout(30000) // 替换成现代Chrome的UA,避免返回旧版页面 .userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36") .referrer("http://www.google.com") .get(); String pageHtml = doc.html(); // 正则匹配Current Version后跟随的版本号字符串 Matcher matcher = Pattern.compile("Current Version.*?>(\\d+(\\.\\d+)+)<").matcher(pageHtml); if (matcher.find()) { latestVersion = matcher.group(1); } Log.e("latestversion", "---" + latestVersion); } catch (Exception e) { e.printStackTrace(); mWsCallerVersionListener.onGetResponse(false); } return new JSONObject(); }
注意:你原来用Float.parseFloat()对比版本号的逻辑有严重缺陷,多段式版本号(比如3.12.2、1.0.21)转浮点数会出现精度丢失、对比错误(比如2.10.0会被判定小于2.9.0),建议改成逐段拆分数字对比,或者用官方androidx.core.content.pm.PackageInfoCompat工具类做版本对比。
方案2:临时修正CSS选择器(不推荐,后续易失效)
如果一定要用DOM选择的方式,当前版本Play商店的版本号节点不能再用固定下标定位,需要遍历同组节点匹配标题拿值,临时可用的选择器参考:
Elements infoNodes = doc.select("div.reAt0 span.htlgb"); // 遍历节点找到前面标题为Current Version的对应节点 for (int i = 0; i < infoNodes.size(); i++) { Element node = infoNodes.get(i); if (node.previousElementSibling() != null && "Current Version".equals(node.previousElementSibling().text().trim())) { latestVersion = node.text().trim(); break; } }
这个方案只是临时适配当前页面结构,只要Google下次调整class名或者节点顺序,逻辑会再次失效。
爬取Play商店页面拿版本号的方案本身就不具备长期可靠性,最稳妥的方案是自己搭建简单的接口托管最新版本号:每次发版上架后手动/自动把最新版本号同步到你自己的服务端,客户端启动时请求自有接口判断是否需要强更,完全不依赖Google的页面结构,不会出现突然失效的问题。
内容的提问来源于stack exchange,提问作者Nitish Mehta

