Android调用OTP接口前如何校验EditText输入的无效手机号
问题核心
你当前使用的android.util.Patterns.PHONE仅做最宽松的通用格式校验,只会判断字符组成、长度是否符合电话号码的通用规则,完全不会校验号码是否符合对应国家运营商的实际放号逻辑,所以像+91-0000000000、+91-0000000011、+91-1234567890这类格式合规但实际不存在的假号会直接漏过。
可行前置校验方案
针对印度(+91)手机号场景,做三层递进校验即可在调用OTP接口前拦截绝大多数假号,不需要引入额外第三方库,本地执行无性能损耗,完全适配输入实时校验、点击按钮前置拦截的场景:
第一层:输入归一化预处理
先清洗用户输入的内容,移除分隔符、特殊符号,剥离国家码拿到纯数字本地号,提前筛掉长度不符合要求的非法输入:
// 印度手机号配置常量 private static final String IN_COUNTRY_CODE = "91"; private static final int IN_LOCAL_MOBILE_LENGTH = 10; private String normalizeIndianPhone(String input) { // 移除所有非数字字符(横杠、空格、括号、+号全部过滤) String digitsOnly = input.replaceAll("[^0-9]", ""); // 处理带国家码的输入:12位长度且开头为91时,截掉前两位国家码 if (digitsOnly.length() == IN_LOCAL_MOBILE_LENGTH + 2 && digitsOnly.startsWith(IN_COUNTRY_CODE)) { digitsOnly = digitsOnly.substring(2); } // 归一化后必须刚好是10位纯数字,否则直接判定无效 return digitsOnly.length() == IN_LOCAL_MOBILE_LENGTH ? digitsOnly : null; }
第二层:特征假号规则拦截
针对典型无效号的固定特征做定向拦截,覆盖你提到的所有无效样例:
- 10位本地号首位为0/1:印度当前有效手机号首位仅开放6/7/8/9号段,0、1开头的号码不存在
- 全号为重复数字:比如0000000000、1111111111这类测试用假号
- 全号为连续顺/逆序数字:比如1234567890、9876543210这类随意输入的顺号
- 前5位全为0:不存在00000开头的印度手机号段
第三层:整合后的完整校验逻辑
替换原有isValidMobile方法内的系统正则逻辑,整合所有校验规则:
private boolean isValidMobile(String phone) { // 第一步:格式归一化校验 String localPhone = normalizeIndianPhone(phone); if (localPhone == null) { return false; } // 第二步:校验首位号段合法性 char firstDigit = localPhone.charAt(0); if (firstDigit != '6' && firstDigit != '7' && firstDigit != '8' && firstDigit != '9') { return false; } // 第三步:拦截全重复数字假号 boolean isAllSame = true; for (int i = 1; i < localPhone.length(); i++) { if (localPhone.charAt(i) != localPhone.charAt(0)) { isAllSame = false; break; } } if (isAllSame) { return false; } // 第四步:拦截连续顺/逆序假号 boolean isSequentialAsc = true; boolean isSequentialDesc = true; for (int i = 1; i < localPhone.length(); i++) { if (localPhone.charAt(i) - localPhone.charAt(i-1) != 1) { isSequentialAsc = false; } if (localPhone.charAt(i-1) - localPhone.charAt(i) != 1) { isSequentialDesc = false; } if (!isSequentialAsc && !isSequentialDesc) { break; } } if (isSequentialAsc || isSequentialDesc) { return false; } // 第五步:拦截前5位全0的假号 if (localPhone.startsWith("00000")) { return false; } // 所有规则校验通过才判定为有效号码 return true; }
补充说明
- 这套规则可以直接放在发送OTP按钮的点击回调里,也可以绑定
EditText的TextWatcher做实时输入提示 - 如果后续需要支持其他国家的手机号,只需要对应修改国家码常量、本地号长度、号段校验规则即可
- 系统自带的
Patterns.PHONE可以作为最外层兜底校验,但不要单独依赖它做号码有效性判断
内容的提问来源于stack exchange,提问作者Kapil Rajput
相关产品推荐
相关产品推荐

