
1. 安卓输入法遮挡 input 的真实场景与排查思路小程序里 input 被输入法挡住是个看起来很小、真机上却能把人折腾半天的坑。我最近在做一个带备注输入的表单页iOS 上一切正常到了几台安卓机上就出问题点进输入框键盘弹起来输入框要么被压在键盘下面要么页面往上顶了一大截顶部标题被顶出屏幕用户根本看不到自己在打什么。更离谱的是同一份代码在不同安卓机型上表现还不一样有的正常上推有的完全不推有的推了但推错位置。这个问题的核心检索词就是「小程序 input 被输入法遮挡」它属于典型的跨端兼容问题。小程序官方给 input 提供了adjust-position属性默认值是true意思是键盘弹起时自动把页面往上推让输入框露出来。理论上够用但安卓阵营的输入法实现五花八门系统 WebView 版本、厂商定制 ROM、输入法 App 自身的高度上报策略都会影响最终效果所以才会出现「部分安卓机不兼容」。适合谁看正在做小程序表单、聊天输入、验证码输入、备注弹窗的开发者尤其是遇到「iOS 正常、安卓翻车」这种情况的同学。下面我会从三条线索切入——adjust-position配置、页面滚动位置、键盘高度监听给出可直接复制的代码和真机验证步骤。先说排查思路别一上来就改代码。第一步确认问题机型是全部安卓还是个别机型是系统输入法还是第三方输入法搜狗、讯飞等第二步确认页面结构input 是普通文档流还是放在position: fixed的弹层里这两种情况处理方式完全不同。第三步打开真机调试看bindfocus回调里event.detail.height到底有没有值、值是多少。很多遮挡问题的根因就是键盘高度没拿到或者拿到了 0。我踩过的坑是一开始只加了cursor-spacing以为能解决结果在部分机型上输入框确实浮起来了但浮的位置不对和键盘之间留了一条缝或者直接重叠。后来才明白cursor-spacing控制的是光标与键盘的距离它依赖系统正确上报键盘高度一旦上报不准这个属性就形同虚设。所以真正稳的方案是关掉自动上推自己监听键盘高度手动控制输入框位置。这也是下面要展开的重点。2. TaoToken 前置准备用 API 调试输入法兼容问题在动手改代码之前先解决一个现实问题真机调试时我们经常需要对比不同模型对同一段兼容代码的分析或者让模型帮忙读一段报错日志。这时候一个稳定的 API 入口就很有用。TaoToken 提供统一的模型调用接口官网地址是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 入口是 https://taotoken.net/api 这个不加 UTM。它的定位是给开发者提供一个聚合式的模型调用层你不需要在多个平台之间来回切换 Key用一套 Base URL 和 Key 就能调用不同模型。对于排查输入法遮挡这种需要反复试错、对比方案的场景能省不少事。比如你可以把bindfocus回调里打印出来的event.detail贴给模型让它帮你判断键盘高度是否异常。接入方式很简单三步拿 Key、配 Base URL、选 Model ID。这三件套在任何支持自定义 API 的工具里都是通用的。如果你用的是 Claude Code 这类编码工具可以在它的配置里填入{ base_url: https://taotoken.net/api, api_key: 你的_API_KEY, model: claude-sonnet-4-20250514 }如果你用的是 Cline 或者带 MCP 的编辑器插件配置项名字可能不同但核心还是这三样Base URL 填https://taotoken.net/apiKey 填你在控制台生成的Model ID 按你需要的模型填。注意 Base URL 不要带 UTM 参数那是给网页访问用的API 调用只认纯域名路径。拿 Key 的入口在控制台的 API Keys 页面模型对话可以在对话页直接试长期做编码和 Agent 任务的话可以看 Coding Plan。这几个入口分别是模型对话https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodel_chatutm_campaignrewriteCoding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite控制台https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewriteAPI Keyshttps://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite接入文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite为什么要在这里提这个因为输入法遮挡的排查过程本质是「改代码 → 真机验证 → 看日志 → 再改」的循环。有一个顺手的模型调用入口能帮你快速理解event.detail.height的异常值、生成对比测试用例、解释不同安卓 WebView 的行为差异。它不是解决遮挡问题的直接工具但能明显加快你的排查节奏。需要说明的是TaoToken 在这里的角色是开发辅助不是让你把生产环境的用户输入直接打到模型上。排查阶段用它来分析日志、生成测试代码是合适的涉及用户隐私的数据不要往外传。3. 可复制配置adjust-position 关闭 键盘高度监听 滚动补偿这一节是核心直接给能跑的代码。整体思路分三步第一把 input 的adjust-position设为false关掉系统自动上推避免它和我们的手动控制打架第二在bindfocus里拿键盘高度赋给外层容器的bottom第三在bindblur里把高度归零。如果输入框在弹层里还要配合滚动补偿。先看 WXML 结构。假设输入框放在一个固定在底部的弹层里view classwx-verify-main stylebottom:{{reasonHeight}}px; input classkey-input value{{inputValue}} typenumber focus{{isFocus}} bindinputlistenKeyInput adjust-position{{false}} show-confirm-bar{{false}} cursor-spacing0 bindfocusbindfocusDialog bindblurbindblurDialog / /view这里几个属性逐个说明。adjust-position{{false}}是关键关掉自动上推。cursor-spacing0让光标紧贴键盘上沿配合手动定位使用。show-confirm-bar{{false}}在数字键盘场景下隐藏确认栏减少高度计算误差。bindfocus和bindblur分别处理聚焦和失焦。对应的 JSPage({ data: { inputValue: , isFocus: false, reasonHeight: 0 }, bindfocusDialog(event) { const vm this; // event.detail.height 是键盘高度部分机型可能为 0 const keyboardHeight event.detail.height || 0; vm.setData({ reasonHeight: keyboardHeight }); }, bindblurDialog(event) { this.setData({ reasonHeight: 0 }); }, listenKeyInput(event) { this.setData({ inputValue: event.detail.value }); } });外层容器用position: fixed; bottom: {{reasonHeight}}px;定位键盘弹起时bottom等于键盘高度输入框就正好贴在键盘上方。键盘收起时bottom归零回到页面底部。但这里有个坑部分安卓机event.detail.height返回 0 或者明显偏小。这时候需要加一层兜底。可以在bindfocus里判断如果高度为 0用一个经验值或者通过wx.getSystemInfoSync()的screenHeight和windowHeight差值来估算bindfocusDialog(event) { let keyboardHeight event.detail.height || 0; if (keyboardHeight 0) { const sysInfo wx.getSystemInfoSync(); // 用屏幕高度减去可视窗口高度粗略估算键盘高度 keyboardHeight sysInfo.screenHeight - sysInfo.windowHeight; } this.setData({ reasonHeight: keyboardHeight }); }如果输入框不在 fixed 弹层里而是在普通文档流中那bottom定位就不适用了。这时候改用滚动补偿在bindfocus里拿到键盘高度后用wx.pageScrollTo把输入框滚到可视区域。可以先通过createSelectorQuery拿到输入框的位置bindfocusDialog(event) { const keyboardHeight event.detail.height || 0; const query wx.createSelectorQuery(); query.select(.key-input).boundingClientRect(); query.selectViewport().scrollOffset(); query.exec((res) { if (!res[0]) return; const inputBottom res[0].bottom; const scrollTop res[1].scrollTop; const windowHeight wx.getSystemInfoSync().windowHeight; const visibleBottom windowHeight - keyboardHeight; if (inputBottom visibleBottom) { const offset inputBottom - visibleBottom 20; wx.pageScrollTo({ scrollTop: scrollTop offset, duration: 200 }); } }); }这段逻辑是算出输入框底部和「可视区域底部窗口高度减键盘高度」的差值如果输入框被挡住了就往下滚相应的距离多留 20px 缓冲。这样即使键盘高度上报有偏差也能保证输入框露出来。配置层面还有一个容易忽略的点页面本身的page.json里如果开了disableScroll: truewx.pageScrollTo会失效滚动补偿就用不了。这种页面只能走 fixed 弹层方案。所以先确认你的页面配置。4. 真机验证从 bindfocus 日志到成功结果代码写完不算完必须真机验证。模拟器的键盘行为和真机差别很大尤其是安卓模拟器基本测不出遮挡问题。验证步骤如下。第一步打开真机调试。在微信开发者工具里点「真机调试」用手机扫码。然后在手机上手点输入框观察开发者工具的 Console 面板看bindfocus有没有触发、event.detail.height打印出来是多少。建议在bindfocusDialog里加一行console.log(keyboard height:, event.detail.height)方便对照。第二步记录三组数据iOS 上的键盘高度、正常安卓机的高度、出问题机型的高度。正常情况下数字键盘高度在 250 到 350 之间单位 px不同分辨率有差异。如果某台机器返回 0 或者 100 以下基本可以确定是键盘高度上报异常需要走兜底逻辑。第三步验证输入框位置。键盘弹起后输入框应该紧贴键盘上沿中间没有明显缝隙也没有重叠。如果输入框浮得太高说明reasonHeight偏大如果还被挡住说明偏小或者滚动补偿没生效。可以临时把reasonHeight显示在页面上方便肉眼观察view styleposition: fixed; top: 10px; left: 10px; z-index: 999; height: {{reasonHeight}} /view第四步测试边界情况。连续快速点击不同输入框看bindblur和bindfocus是否成对触发reasonHeight有没有残留。切换输入法系统输入法 ↔ 第三方输入法看高度是否变化。旋转屏幕如果支持横屏看定位是否错乱。这些边界情况往往是线上问题的来源。第五步验证失焦后的恢复。键盘收起后reasonHeight应该归零输入框回到原位页面滚动位置也应该恢复正常。如果页面停在滚动后的位置回不去需要在bindblur里补一个wx.pageScrollTo回到原位置或者记录聚焦前的scrollTop失焦时还原。成功的结果是在之前出问题的安卓机型上点输入框键盘弹起输入框稳稳贴在键盘上方页面没有异常跳动输入内容可见收起键盘后一切复原。如果达到了这个效果说明方案生效。这里补充一个验证技巧用wx.onKeyboardHeightChange监听键盘高度变化。这个 API 在部分基础库版本上可用能实时拿到键盘高度比bindfocus的一次性上报更可靠。用法wx.onKeyboardHeightChange((res) { this.setData({ reasonHeight: res.height }); });注意这个监听是全局的要在onLoad里注册onUnload里用wx.offKeyboardHeightChange取消避免内存泄漏。它和bindfocus方案可以二选一也可以结合使用以onKeyboardHeightChange为准bindfocus作为兜底。5. 常见报错排查401、local proxy failed、reading choices、OAuth排查过程中除了遮挡本身还会遇到一些和 API 调用、工具配置相关的报错。这些报错容易让人误以为是代码问题其实是配置没对上。逐个说。401 Unauthorized这个最常见出现在你调用模型 API 时。原因通常是 API Key 填错、Key 过期、或者 Base URL 和 Key 不匹配。检查三件套Base URL 是不是https://taotoken.net/apiKey 是不是从控制台 API Keys 页面复制的完整字符串Model ID 是不是当前账号有权限的模型。注意 Base URL 末尾不要多加/v1之类的路径除非文档明确要求。如果用的是 Claude Code检查它的配置文件里base_url和api_key字段名是否正确。local proxy failed这个报错通常出现在本地工具尝试走代理连接时。如果你在工具里配置了本地代理端口但代理服务没启动就会报这个。解决方法是检查工具的代理设置把不需要的代理关掉直连https://taotoken.net/api。注意这里说的是工具自身的网络配置不是让你去搞什么网络加速就是普通的本地端口检查。reading choices 相关报错这类报错一般出现在解析模型返回结构时比如Cannot read property choices of undefined。原因是返回体不是预期的 OpenAI 兼容格式可能是请求路径不对、或者模型返回了错误信息。先打印完整返回体看error字段再对照接入文档确认请求格式。常见错误是请求体里model字段拼错或者messages数组格式不对。OAuth 相关报错如果你用的是需要 OAuth 授权的工具比如某些 CLI报 OAuth 失败通常是回调地址不对或者 token 过期。检查工具的 OAuth 配置重新走一遍授权流程。如果工具支持 API Key 模式优先用 API Key比 OAuth 少一层坑。把这几类报错和输入法遮挡问题分开看遮挡是前端渲染问题报错是 API 调用问题两者不要混在一起排查。建议先确保 API 调用通了能正常拿到模型返回再专心调前端定位。否则你会分不清是键盘高度没拿到还是请求根本没发出去。排查时养成看日志的习惯。bindfocus里打印event.detailAPI 调用处打印完整请求和响应工具配置处确认三件套。日志清晰了问题定位就快。6. 语义一致收尾把方案落到你的项目里回到最开始的问题小程序 input 被输入法遮挡本质是系统自动上推在部分安卓机上不可靠。解决方案不是找一个万能属性而是关掉自动上推自己接管键盘高度和输入框定位。核心三件套是adjust-position{{false}}、bindfocus拿高度、bindblur归零配合滚动补偿处理文档流场景。落地时按这个顺序来先确认页面结构fixed 弹层还是文档流选对应方案再确认基础库版本决定用bindfocus还是onKeyboardHeightChange然后加兜底逻辑处理高度为 0 的机型最后真机验证覆盖系统输入法和第三方输入法。如果你在排查过程中需要快速对比不同模型对兼容代码的分析或者让模型帮你读日志可以用 TaoToken 的 API 入口 https://taotoken.net/api Key 在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite 拿接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。长期做编码和 Agent 任务的话Coding Plan 入口是 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite 。最后留一个实用技巧把reasonHeight的兜底逻辑封装成一个函数不同页面复用。输入框多的时候给每个 input 绑定同一套bindfocus/bindblur用data-属性区分是哪个输入框避免重复写逻辑。这样下次再遇到新的安卓机型改一处就够了。