移动调试Skill mobile-debugging

移动调试技能用于在移动设备上远程访问JavaScript控制台和调试网页,包括使用Eruda、vConsole等工具,以及Chrome、Safari的远程调试方法。适用于开发人员调试移动端网页问题、测试响应式设计、捕获控制台错误等。关键词:移动调试、JavaScript控制台、网页调试、移动设备、远程调试。

前端开发 0 次安装 0 次浏览 更新于 3/15/2026

名称: 移动调试 描述: 在移动设备上远程访问JavaScript控制台和调试。用于调试手机/平板上的网页、在没有桌面开发者工具的情况下访问控制台错误、在真实设备上测试响应式设计或诊断移动特定问题。涵盖Eruda、vConsole、Chrome/Safari远程调试和云测试平台。

移动调试方法论

在移动设备上访问JavaScript控制台和调试网页的模式,无需传统桌面开发者工具。

快速开始:在任何页面注入控制台

Eruda书签工具(推荐)

在移动浏览器中添加此书签,然后在任何页面点击它:

javascript:(function(){var script=document.createElement('script');script.src='https://cdn.jsdelivr.net/npm/eruda';document.body.append(script);script.onload=function(){eruda.init();}})();

vConsole书签工具

javascript:(function(){var script=document.createElement('script');script.src='https://unpkg.com/vconsole@latest/dist/vconsole.min.js';document.body.append(script);script.onload=function(){new VConsole();}})();

页面内控制台工具

Eruda设置

Eruda在浮动面板中提供完整的开发者工具类体验。

<!-- CDN(仅开发) -->
<script src="https://cdn.jsdelivr.net/npm/eruda"></script>
<script>eruda.init();</script>

<!-- 条件加载(生产环境推荐) -->
<script>
(function() {
    var src = 'https://cdn.jsdelivr.net/npm/eruda';
    // 仅当?eruda=true或localStorage标志设置时加载
    if (!/eruda=true/.test(window.location) &&
        localStorage.getItem('active-eruda') !== 'true') return;

    var script = document.createElement('script');
    script.src = src;
    script.onload = function() { eruda.init(); };
    document.body.appendChild(script);
})();
</script>
// NPM安装
// npm install eruda --save-dev

import eruda from 'eruda';

// 使用选项初始化
eruda.init({
    container: document.getElementById('eruda-container'),
    tool: ['console', 'elements', 'network', 'resources', 'info'],
    useShadowDom: true,
    autoScale: true
});

// 添加自定义按钮
eruda.add({
    name: '清除存储',
    init($el) {
        $el.html('<button>清除所有存储</button>');
        $el.find('button').on('click', () => {
            localStorage.clear();
            sessionStorage.clear();
            console.log('存储已清除');
        });
    }
});

// 完成后移除
eruda.destroy();

Eruda特性:

  • 控制台(日志、错误、警告)
  • 元素(DOM检查器)
  • 网络(XHR/fetch请求)
  • 资源(localStorage、cookies、sessionStorage)
  • 源(页面源代码)
  • 信息(页面/设备信息)
  • 片段(保存的代码片段)

vConsole设置

更轻量级的替代方案,微信调试的官方工具。

<!-- CDN -->
<script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script>
<script>
var vConsole = new VConsole();
</script>
// NPM
// npm install vconsole

import VConsole from 'vconsole';

// 使用选项初始化
const vConsole = new VConsole({
    theme: 'dark',
    onReady: function() {
        console.log('vConsole已就绪');
    },
    log: {
        maxLogNumber: 1000
    }
});

// 动态配置
vConsole.setOption('log.maxLogNumber', 5000);

// 完成后销毁
vConsole.destroy();

vConsole特性:

  • 日志面板(console.log、info、warn、error)
  • 系统面板(设备信息)
  • 网络面板(XHR、fetch)
  • 元素面板(DOM树)
  • 存储面板(cookies、localStorage)

对比:Eruda vs vConsole

特性 Eruda vConsole
大小 ~100KB ~85KB
DOM编辑 仅查看
网络详情 完整 基本
插件系统
暗色主题 通过插件 内置
最适合 完整调试 快速日志记录

原生远程调试

Chrome开发者工具(Android)

# 1. 在Android上启用USB调试
#    设置 → 开发者选项 → USB调试 = 开启

# 2. 通过USB连接到计算机

# 3. 在计算机上打开Chrome,导航到:
#    chrome://inspect#devices

# 4. 启用“发现USB设备”

# 5. 在Android设备上接受调试提示

# 6. 点击要调试的页面旁边的“检查”

本地主机的端口转发:

# 在chrome://inspect中,点击“端口转发”
# 添加:localhost:3000 → localhost:3000
# 现在Android Chrome可以在localhost:3000访问开发服务器

Safari网页检查器(iOS)

# 1. 在iPhone/iPad上:
#    设置 → Safari → 高级 → 网页检查器 = 开启

# 2. 在Mac上:
#    Safari → 偏好设置 → 高级 → “显示开发菜单” = 开启

# 3. 通过USB连接设备(或启用Wi-Fi调试)

# 4. 在Mac上打开Safari:
#    开发 → [设备名称] → [要调试的页面]

# 无线调试(初始USB设置后):
#    开发 → [设备] → 通过网络连接

Firefox远程调试(Android)

# 1. 在Android Firefox上:
#    设置 → 高级 → 远程调试 = 开启

# 2. 在桌面Firefox上:
#    打开about:debugging

# 3. 通过USB连接Android

# 4. 在about:debugging中启用USB设备

# 5. 点击设备旁边的“连接”

iOS调试无需Mac

使用ios-webkit-debug-proxy

# 在Windows上安装(通过Scoop)
scoop bucket add extras
scoop install ios-webkit-debug-proxy

# 在Linux上安装
sudo apt-get install ios-webkit-debug-proxy

# 在Mac上安装
brew install ios-webkit-debug-proxy

# 运行代理
ios_webkit_debug_proxy -f chrome-devtools://devtools/bundled/inspector.html

# 连接到http://localhost:9221查看连接的设备

商业工具:Inspect.dev

Inspect.dev从Windows/Linux提供iOS调试,具有熟悉的开发者工具界面。

# 从https://inspect.dev/下载
# 1. 安装应用程序
# 2. 通过USB连接iOS设备
# 3. 在iOS上启用网页检查器
# 4. Inspect.dev自动检测页面
# 5. 点击打开开发者工具界面

云测试平台

LambdaTest(免费增值)

# LambdaTest提供带控制台访问的真实设备云
# 免费层:100分钟/月

import requests

# LambdaTest REST API用于自动化
LAMBDATEST_API = "https://api.lambdatest.com/automation/api/v1"

# 对于手动测试:
# 1. 访问https://www.lambdatest.com/
# 2. 选择设备/浏览器
# 3. 输入URL
# 4. 工具栏中提供开发者工具

# Selenium/Playwright集成用于自动控制台捕获
from playwright.sync_api import sync_playwright

def test_on_lambdatest():
    with sync_playwright() as p:
        # 连接到LambdaTest
        browser = p.chromium.connect(
            f"wss://cdp.lambdatest.com/playwright?capabilities="
            f"{{\"browserName\":\"Chrome\",\"platform\":\"android\"}}"
        )
        page = browser.new_page()

        # 捕获控制台日志
        logs = []
        page.on('console', lambda msg: logs.append(msg.text()))

        page.goto('https://example.com')
        browser.close()

        return logs

BrowserStack

# BrowserStack:$29+/月,10,000+真实设备

from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities

def get_browserstack_driver():
    """创建带控制台日志记录的BrowserStack WebDriver。"""

    capabilities = {
        'browserName': 'chrome',
        'device': 'Samsung Galaxy S21',
        'realMobile': 'true',
        'os_version': '11.0',
        'browserstack.console': 'verbose',  # 捕获控制台日志
        'browserstack.networkLogs': 'true',
        'browserstack.user': 'YOUR_USERNAME',
        'browserstack.key': 'YOUR_KEY'
    }

    driver = webdriver.Remote(
        command_executor='https://hub-cloud.browserstack.com/wd/hub',
        desired_capabilities=capabilities
    )

    return driver

# 测试后,从BrowserStack仪表板或API检索日志

编程式控制台捕获

Playwright控制台捕获

const { chromium, devices } = require('playwright');

async function captureConsoleLogs(url) {
    const browser = await chromium.launch();

    // 模拟移动设备
    const context = await browser.newContext({
        ...devices['iPhone 13']
    });

    const page = await context.newPage();

    // 捕获所有控制台消息
    const logs = [];
    page.on('console', msg => {
        logs.push({
            type: msg.type(),
            text: msg.text(),
            location: msg.location(),
            timestamp: new Date().toISOString()
        });
    });

    // 捕获页面错误
    const errors = [];
    page.on('pageerror', error => {
        errors.push({
            message: error.message,
            stack: error.stack,
            timestamp: new Date().toISOString()
        });
    });

    // 捕获失败请求
    const failedRequests = [];
    page.on('requestfailed', request => {
        failedRequests.push({
            url: request.url(),
            failure: request.failure().errorText,
            timestamp: new Date().toISOString()
        });
    });

    await page.goto(url);
    await page.waitForLoadState('networkidle');

    await browser.close();

    return { logs, errors, failedRequests };
}

// 用法
captureConsoleLogs('https://example.com')
    .then(result => console.log(JSON.stringify(result, null, 2)));

Puppeteer控制台捕获

const puppeteer = require('puppeteer');

async function debugMobilePage(url) {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();

    // 设置移动视口
    await page.setViewport({
        width: 375,
        height: 812,
        isMobile: true,
        hasTouch: true
    });

    // 移动用户代理
    await page.setUserAgent(
        'Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) ' +
        'AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1'
    );

    // 控制台捕获带完整详情
    page.on('console', async msg => {
        const args = await Promise.all(
            msg.args().map(arg => arg.jsonValue().catch(() => arg.toString()))
        );

        console.log(`[${msg.type().toUpperCase()}]`, ...args);

        // 获取源位置
        const location = msg.location();
        if (location.url) {
            console.log(`  位于 ${location.url}:${location.lineNumber}`);
        }
    });

    // 未处理的承诺拒绝
    page.on('pageerror', err => {
        console.error('[页面错误]', err.message);
    });

    await page.goto(url, { waitUntil: 'networkidle0' });

    // 执行JavaScript并捕获结果
    const result = await page.evaluate(() => {
        // 检查常见移动问题
        return {
            viewportWidth: window.innerWidth,
            devicePixelRatio: window.devicePixelRatio,
            touchSupport: 'ontouchstart' in window,
            errors: window.__capturedErrors || []
        };
    });

    console.log('页面信息:', result);

    await browser.close();
}

错误监控服务

Sentry集成

// npm install @sentry/browser

import * as Sentry from '@sentry/browser';

Sentry.init({
    dsn: 'YOUR_SENTRY_DSN',
    environment: 'production',

    // 捕获console.error
    integrations: [
        new Sentry.BrowserTracing(),
        new Sentry.Replay()  // 用于调试的会话回放
    ],

    // 采样率
    tracesSampleRate: 0.1,
    replaysSessionSampleRate: 0.1,
    replaysOnErrorSampleRate: 1.0,

    beforeSend(event) {
        // 过滤或修改事件
        return event;
    }
});

// 手动错误捕获
try {
    riskyOperation();
} catch (error) {
    Sentry.captureException(error);
}

// 添加上下文
Sentry.setUser({ id: 'user123' });
Sentry.setTag('page', 'checkout');

LogRocket用于会话回放

// npm install logrocket

import LogRocket from 'logrocket';

LogRocket.init('your-app/your-project');

// 识别用户
LogRocket.identify('user123', {
    name: 'Test User',
    email: 'user@example.com'
});

// 控制台日志自动捕获
console.log('此内容出现在LogRocket中');

// 手动日志记录
LogRocket.log('自定义事件', { data: 'value' });

// 跟踪错误
LogRocket.captureException(new Error('出现错误'));

Android屏幕镜像与Scrcpy

# 安装scrcpy
# Windows: scoop install scrcpy
# Mac: brew install scrcpy
# Linux: apt install scrcpy

# 基本镜像
scrcpy

# 带特定选项
scrcpy --max-size 1024 --bit-rate 2M

# 无线连接(初始USB后)
adb tcpip 5555
adb connect <设备IP>:5555
scrcpy

# 录制会话
scrcpy --record session.mp4

# 镜像时关闭设备屏幕
scrcpy --turn-screen-off

移动调试工作流

┌─────────────────────────────────────────────────────────────────┐
│                  移动调试决策树                  │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  问:您是否有物理访问设备?                  │
│      │                                                           │
│      ├─ 是:能否通过USB连接?                           │
│      │   │                                                       │
│      │   ├─ Android:使用Chrome开发者工具远程                 │
│      │   │           chrome://inspect#devices                    │
│      │   │                                                       │
│      │   └─ iOS:有Mac吗?                                    │
│      │       │                                                   │
│      │       ├─ 是:使用Safari网页检查器                   │
│      │       │                                                   │
│      │       └─ 否:使用Inspect.dev或                          │
│      │              ios-webkit-debug-proxy                       │
│      │                                                           │
│      └─ 无USB:通过书签工具注入Eruda/vConsole           │
│                                                                  │
│  问:远程/生产调试?                                │
│      │                                                           │
│      ├─ 添加条件Eruda加载                           │
│      │  (?eruda=true参数)                                 │
│      │                                                           │
│      └─ 设置Sentry/LogRocket进行错误监控            │
│                                                                  │
│  问:自动化测试?                                          │
│      │                                                           │
│      ├─ 使用移动模拟的Playwright/Puppeteer              │
│      │                                                           │
│      └─ 云平台(LambdaTest、BrowserStack)              │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

常见移动调试问题

触摸事件未触发

// 检查触摸事件是否支持
eruda.init();
console.log('触摸支持:', 'ontouchstart' in window);
console.log('指针事件:', 'onpointerdown' in window);

// 调试触摸事件
document.addEventListener('touchstart', e => {
    console.log('触摸开始', e.touches.length, '个触摸点');
}, { passive: true });

document.addEventListener('click', e => {
    console.log('点击位于', e.clientX, e.clientY);
});

视口问题

// 记录视口信息
console.log('视口:', {
    innerWidth: window.innerWidth,
    innerHeight: window.innerHeight,
    outerWidth: window.outerWidth,
    outerHeight: window.outerHeight,
    devicePixelRatio: window.devicePixelRatio,
    orientation: screen.orientation?.type
});

// 检查meta视口
const viewport = document.querySelector('meta[name="viewport"]');
console.log('视口meta:', viewport?.content);

性能调试

// 检查性能计时
const perf = performance.getEntriesByType('navigation')[0];
console.log('页面加载计时:', {
    dns: perf.domainLookupEnd - perf.domainLookupStart,
    tcp: perf.connectEnd - perf.connectStart,
    request: perf.responseStart - perf.requestStart,
    response: perf.responseEnd - perf.responseStart,
    domParsing: perf.domInteractive - perf.responseEnd,
    domComplete: perf.domComplete - perf.domInteractive,
    total: perf.loadEventEnd - perf.navigationStart
});

// 检查内存(仅Chrome)
if (performance.memory) {
    console.log('内存:', {
        usedJSHeapSize: (performance.memory.usedJSHeapSize / 1048576).toFixed(2) + ' MB',
        totalJSHeapSize: (performance.memory.totalJSHeapSize / 1048576).toFixed(2) + ' MB'
    });
}

平台对比

工具 成本 平台 设置难度 最适合
Eruda 免费 所有浏览器 简单(书签工具) 快速调试
vConsole 免费 所有浏览器 简单 微信应用
Chrome远程 免费 仅Android 中等 完整开发者工具
Safari检查器 免费 仅iOS 简单(需要Mac) 完整开发者工具
Inspect.dev 付费 从任何操作系统iOS 简单 无需Mac的iOS
LambdaTest 免费增值 所有 简单 云测试
BrowserStack 付费 所有 简单 真实设备
Sentry 免费增值 所有 中等 错误监控