资深无脑詹黑的爷爷 發表於 2025-8-29 08:33:05

Android端验证码自动获取与填充的实战方案

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li>背景与痛点</li><li>技术方案概述</li><li>核心代码实现</li><ul class="second_class_ul"><li>短信工具类 (SmsUtils)</li><li>登录页面集成 (LoginPage)</li></ul><li>关键技术点解析</li><ul class="second_class_ul"><li>1. ADB访问短信内容提供器</li><li>2. 短信时效性验证</li><li>3. 重试机制</li><li>4. 关键字过滤</li></ul><li>应用效果与价值</li><ul class="second_class_ul"></ul><li>注意事项与优化方向</li><ul class="second_class_ul"></ul><li>结语</li><ul class="second_class_ul"></ul></ul></div><blockquote><p>解决正式环境测试账号受限的优雅方案</p></blockquote>
<p class="maodian"></p><h2>背景与痛点</h2>
<p>在移动应用自动化测试过程中,我们经常会遇到一个棘手的问题:正式环境的接口由于安全考虑,不愿意向测试团队开放测试账号。这意味着我们需要使用真实账号进行测试,而其中最麻烦的环节就是验证码的获取与填写。</p>
<p>传统的解决方案要么依赖mock数据(在正式环境不可行),要么手动查看手机短信并输入验证码(效率低下且无法自动化)。针对这一痛点,我开发了一个基于ADB的Android短信验证码自动获取工具,完美解决了正式环境下的验证码自动化测试问题。</p>
<p class="maodian"></p><h2>技术方案概述</h2>
<p>本方案的核心思路是通过ADB命令访问Android系统的短信内容提供器(Content Provider),获取短信内容后通过正则表达式提取验证码,最后自动填充到应用输入框中。</p>
<p><strong>主要技术组件:</strong></p>
<ul><li>ADB命令操作</li><li>Android Content Provider访问</li><li>正则表达式匹配</li><li>自动化测试集成</li></ul>
<p class="maodian"></p><h2>核心代码实现</h2>
<p class="maodian"></p><h3>短信工具类 (SmsUtils)</h3>
<div class="jb51code"><pre class="brush:java;">import subprocess
import time
import re
from utils.logger_until import Logger

class SmsUtils:
    def __init__(self):
      self.logger = Logger(name=__name__).logger

    def get_sms_data_from_device(self):
      """从安卓设备读取所有短信"""
      command = "adb shell content query --uri content://sms/inbox --projection _id,address,date,body"
      result = subprocess.run(command, shell=True, capture_output=True, text=True, encoding="utf-8")
      
      if result.returncode != 0:
            raise Exception("设备获取短信失败,请检查ADB连接")
      
      # 解析短信数据
      parsed_sms = []
      for line in result.stdout.splitlines():
            sms_dict = {}
            for item in line.split(","):
                key_value = item.split("=")
                if len(key_value) == 2:
                  sms_dict.strip()] = key_value.strip()
            parsed_sms.append(sms_dict)
      
      return parsed_sms

    @staticmethod
    def filter_sms_by_keyword(sms_data, keyword):
      """根据关键字筛选短信"""
      return

    def get_latest_sms_by_timestamp(self, sms_data):
      """获取最新时间戳的短信"""
      sms_data_with_date =
      sorted_sms = sorted(sms_data_with_date, key=lambda x: int(x['date']), reverse=True)
      
      if not sorted_sms:
            return None
            
      # 验证短信时效性(10分钟内)
      latest_sms = sorted_sms
      sms_timestamp = int(latest_sms['date'])
      current_timestamp = int(time.time() * 1000)
      time_diff = current_timestamp - sms_timestamp
      
      if time_diff &lt;= 600000:# 10分钟
            return latest_sms
      else:
            self.logger.error(f"验证码已过期,时间差:{time_diff//60000}分钟")
            return False

    def extract_verification_code(self, sms_body):
      """从短信内容提取验证码"""
      try:
            if isinstance(sms_body, dict):
                number_body = str(sms_body.get("body", ""))
                self.logger.info(f"原始短信内容: {number_body}")
                match = re.search(r"\d{6}", number_body)
                if match:
                  return match.group(0)
            return None
      except Exception as e:
            self.logger.error(f"验证码提取错误: {e}")
            raise

    @staticmethod
    def get_latest_verification_code(keyword="魔意科技"):
      """获取最新验证码(整合方法)"""
      sms = SmsUtils()
      sms_data = sms.get_sms_data_from_device()
      filtered_sms = sms.filter_sms_by_keyword(sms_data, keyword)
      latest_sms = sms.get_latest_sms_by_timestamp(filtered_sms)
      
      if latest_sms:
            return sms.extract_verification_code(latest_sms)
      else:
            return False
</pre></div>
<p class="maodian"></p><h3>登录页面集成 (LoginPage)</h3>
<div class="jb51code"><pre class="brush:java;">import time
from functools import wraps
from utils.sms_util import SmsUtils

# 重试装饰器
def retry(times=3, delay=2):
    def decorator(func):
      @wraps(func)
      def wrapper(*args, **kwargs):
            last_exception = None
            for attempt in range(times):
                try:
                  return func(*args, **kwargs)
                except Exception as e:
                  last_exception = e
                  time.sleep(delay)
                  print(f"第{attempt+1}次重试失败,剩余{times - attempt - 1}次重试")
            if last_exception:
                raise last_exception
      return wrapper
    return decorator

class LoginPage(BasePage):
    def __init__(self, device_manager):
      super().__init__(device_manager)
      self.logger = Logger(name=__name__).logger
   
    @retry(times=3, delay=15)
    def auto_fill_verification_code(self, keyword="魔意科技"):
      """自动填充验证码(带重试机制)"""
      verification_code = SmsUtils.get_latest_verification_code(keyword)
      if verification_code:
            self.logger.info(f"验证码提取成功: {verification_code}")
            self.input_text("phone_code_input", verification_code)
            self.logger.info(f"验证码已自动填充")
      else:
            self.logger.error("未找到有效验证码")
            raise ValueError("验证码提取失败")
   
    def _perform_login_flow(self, account: str, locator_prefix: str):
      """执行登录流程"""
      # 确保在正确的登录方式页面
      if not self.assert_element_visible(f"{locator_prefix}_input"):
            self.click_element(f"switch_to_{locator_prefix}")
      
      # 输入账号并获取验证码
      self.input_text(f"{locator_prefix}_input", account)
      self.click_element("phone_code_get_captcha")
      
      # 等待并自动填充验证码
      time.sleep(10)# 等待短信发送
      self.auto_fill_verification_code()
      
      # 后续登录操作...
</pre></div>
<p class="maodian"></p><h2>关键技术点解析</h2>
<p class="maodian"></p><h3>1. ADB访问短信内容提供器</h3>
<p>通过<code>adb shell content query</code>命令直接访问Android系统的短信数据库,这是本方案的核心:</p>
<div class="jb51code"><pre class="brush:bash;">adb shell content query --uri content://sms/inbox --projection _id,address,date,body
</pre></div>
<p class="maodian"></p><h3>2. 短信时效性验证</h3>
<p>考虑到验证码的有效期,我们添加了时间戳检查逻辑,确保只使用10分钟内的最新验证码。</p>
<p class="maodian"></p><h3>3. 重试机制</h3>
<p>通过装饰器实现了优雅的重试机制,应对短信延迟到达的情况,提高测试稳定性。</p>
<p class="maodian"></p><h3>4. 关键字过滤</h3>
<p>支持通过关键字过滤短信,确保获取到的是目标应用发送的验证码,避免其他短信干扰。</p>
<p class="maodian"></p><h2>应用效果与价值</h2>
<ol><li><strong>完全自动化</strong>:解决了正式环境验证码测试的最后一公里问题</li><li><strong>提高效率</strong>:无需人工干预查看和输入验证码</li><li><strong>增强稳定性</strong>:重试机制和时效验证确保测试可靠性</li><li><strong>易于集成</strong>:模块化设计,可以轻松集成到现有测试框架中</li></ol>
<p class="maodian"></p><h2>注意事项与优化方向</h2>
<ol><li><strong>权限要求</strong>:需要授予应用读取短信的权限(Android 6.0+需要动态申请)</li><li><strong>兼容性</strong>:不同Android版本短信数据库结构可能略有差异</li><li><strong>安全考虑</strong>:正式环境中使用需注意隐私保护问题</li><li><strong>扩展性</strong>:可考虑支持多种验证码格式(4位、8位等)</li></ol>
<p>未来可考虑扩展为支持多种验证方式(邮箱验证码、语音验证码等)的统一验证码获取平台。</p>
<p class="maodian"></p><h2>结语</h2>
<p>这个Android验证码自动获取方案已经在我们项目中稳定运行,大大提升了正式环境自动化测试的效率和可靠性。希望这个方案对大家有所启发,也欢迎交流更好的实现思路。</p>
<p>以上就是Android端验证码自动获取与填充的实战方案的详细内容,更多关于Android验证码自动获取与填充的资料请关注琼殿技术社区其它相关文章!</p>
                           
                            <div class="art_xg">
                              <b>您可能感兴趣的文章:</b><ul><li>Android实现获取短信验证码并自动填充</li><li>Android 中使用ContentObserver模式获取短信用正则自动填充验证码</li><li>Android获取验证码倒计时实现代码</li><li>Android实现点击获取验证码60秒后重新获取功能</li><li>Android实现获取短信验证码并自动填写功能</li></ul>
                            </div>

                        </div>
                        <!--endmain-->
頁: [1]
查看完整版本: Android端验证码自动获取与填充的实战方案