{"id":16434381,"url":"https://github.com/tommylemon/uigo","last_synced_at":"2025-07-26T15:10:44.368Z","repository":{"id":163612090,"uuid":"268064039","full_name":"TommyLemon/UIGO","owner":"TommyLemon","description":"📱 零代码快准稳 UI 智能录制回放平台 🚀 3 像素内自动精准定位，2 毫秒内自动精准等待，用户包含腾讯，应微信团队邀请分享了 零代码测试工具与实践(API•单元•UI) 📱 Coding-free, fast, accurate and stable UI replayer 🚀 Incredible ±3px auto locating and ±2ms auto waiting. Used by Tencent, invited by WeChat team to share","archived":false,"fork":false,"pushed_at":"2024-08-18T14:31:26.000Z","size":10301,"stargazers_count":75,"open_issues_count":0,"forks_count":9,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-04-08T04:41:18.196Z","etag":null,"topics":["automation","autotest","autotesting","low-code","lowcode","no-code","nocode","playback","recorder","replayer","ui-test","ui-testing","uiautomation","uitest","uitesting"],"latest_commit_sha":null,"homepage":"http://apijson.cn/ui/","language":"Java","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/TommyLemon.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-05-30T11:14:41.000Z","updated_at":"2025-03-23T06:04:30.000Z","dependencies_parsed_at":"2024-06-08T17:25:12.620Z","dependency_job_id":"c18c0660-010f-4991-ae85-93aad2dca9b4","html_url":"https://github.com/TommyLemon/UIGO","commit_stats":{"total_commits":230,"total_committers":1,"mean_commits":230.0,"dds":0.0,"last_synced_commit":"96a4e899de5130a14ea9aa36ab9d05edd1f7fe9d"},"previous_names":["tommylemon/uigo"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/TommyLemon/UIGO","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TommyLemon%2FUIGO","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TommyLemon%2FUIGO/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TommyLemon%2FUIGO/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TommyLemon%2FUIGO/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TommyLemon","download_url":"https://codeload.github.com/TommyLemon/UIGO/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TommyLemon%2FUIGO/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267184060,"owners_count":24049126,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-26T02:00:08.937Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["automation","autotest","autotesting","low-code","lowcode","no-code","nocode","playback","recorder","replayer","ui-test","ui-testing","uiautomation","uitest","uitesting"],"created_at":"2024-10-11T08:48:59.786Z","updated_at":"2025-07-26T15:10:44.361Z","avatar_url":"https://github.com/TommyLemon.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\" style=\"text-align:center;\"\u003e\n  UIGO\n\u003c/h1\u003e\n \n\u003cp align=\"center\"\u003e📱 零代码快准稳 UI 智能录制回放平台 🚀\u003c/p\u003e\n\u003cp align=\"center\"\u003e3 像素内自动精准定位，2 毫秒内自动精准等待，录制回放快、准、稳！\u003c/p\u003e\n\u003cp align=\"center\" \u003e\n  \u003ca href=\"https://github.com/TommyLemon/UIGO/tree/master/UIAuto-Android\"\u003e\u003cimg src=\"https://img.shields.io/badge/Demo-Android26%2B-brightgreen.svg?style=flat\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/TommyLemon/UIGO/tree/master/APIJSONApp\"\u003e\u003cimg src=\"https://img.shields.io/badge/App-Android26%2B-brightgreen.svg?style=flat\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/APIJSON/APIJSON-Demo/tree/master/APIJSON-Java-Server/APIJSONBoot\"\u003e\u003cimg src=\"https://img.shields.io/badge/Server-Java1.8%2B-brightgreen.svg?style=flat\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/TommyLemon/UIGO/tree/master/MySQL\"\u003e\u003cimg src=\"https://img.shields.io/badge/MySQL-5.7%2B-brightgreen.svg?style=flat\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\u003cp align=\"center\" \u003e\n  \u003ca href=\"https://deepwiki.com/TommyLemon/UIGO\"\u003eEnglish\u003c/a\u003e\n  \u003ca href=\"https://github.com/TommyLemon/UIGO#%E7%A4%BA%E4%BE%8B%E9%A1%B9%E7%9B%AE\"\u003e录制回放\u003c/a\u003e\n  \u003ca href=\"https://github.com/TommyLemon/UIGO#%E5%BF%AB%E9%80%9F%E4%B8%8A%E6%89%8B\"\u003e快速上手\u003c/a\u003e\n  \u003ca href=\"http://apijson.cn/ui\"\u003e在线工具\u003c/a\u003e\n  \u003ca href=\"https://deepwiki.com/TommyLemon/UIGO\"\u003eAI 问答\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\" \u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/TommyLemon/UIGO/master/logo.png\" /\u003e\n\u003c/p\u003e\n\n---\n\u003cbr /\u003e\n\n\u003cp align=\"center\" \u003e\n\u003cimg width=\"720\" src=\"https://github.com/TommyLemon/UIGO/assets/5738175/49edbcdb-2bc6-4dfb-bd30-4f9aaafe4e25\" /\u003e\n\u003c/p\u003e\n\n\u003cimg width=\"1280\" src=\"https://github.com/TommyLemon/UIGO/assets/5738175/54cf82d0-99b0-4085-ab89-d54ff95ef4c4\" href=\"https://www.bilibili.com/video/BV1wA4m137ha\" /\u003e\n\u003cimg width=\"1280\" src=\"https://github.com/TommyLemon/UIGO/assets/5738175/032de745-e49a-43f3-b368-84fdbd6a97d7\" href=\"https://search.bilibili.com/all?keyword=UIGO\" /\u003e\n\n## UIGO - 📱 零代码快准稳 UI 智能录制回放平台 🚀 \n**3 像素内自动精准定位，2 毫秒内自动精准等待，录制回放快、准、稳！**\u003cbr /\u003e\n适用于 一次录制到处回放、反复回归界面操作、App UI/功能 自动化测试、\u003cbr /\u003e\n帮助开发快速复现和排查 bug、方便判断 bug 原因出在前端还是后端 等，\u003cbr /\u003e\n**大量减少耗时费力又无聊的重复手工操作，大幅提高手工和自动化测试效率，**\u003cbr /\u003e\n**强力杜绝 测试和开发、前端和后端 关于缺陷单踢皮球等各种低效扯皮内耗！**\u003cbr /\u003e\n\n**用户包含腾讯，应微信团队邀请分享了 零代码测试工具与实践(API•单元•UI)**\n\n### 支持功能\n* **零代码 录制和回放 触屏、按键、键盘、数据 等**\n* **支持 16:9 标准屏、19.5:9 全面屏等各种设备屏幕**\n* **支持原生页面、内置 H5 网页、浏览器加载网页等**\n* 支持 Android 真机、Studio/Genymotion 等模拟器\n* **单双指点击、长按、滑动、缩放各种像素级精细操作**\n* **自动精准等待、模拟 HTTP API 的请求和响应数据**\n* **不同机型录制回放偏差基本仅在 3 像素、2 毫秒 内**\n* **可从任意界面开始和停止录制、回放，绕过登录问题**\n* 可自动对关键步骤截屏，方便对比回放与录制差异\n* **可自动和手动选择 View 及触摸区域、贴靠方式等**\n* 可保存录制步骤相关数据到后端数据库及从后端下载\n* 可用管理端网页浏览检索用例和远程控制录制回放\n* 附带 UnitAuto-机器学习零代码自动化单元测试\n* 中文和英语双语文案，根据系统语言设置自动切换\n\n### 特点优势\n相比各种 UI 录制回放/自动化测试 的 其它平台/工具/框架：\u003cbr /\u003e\u003cbr /\u003e\n1.它们录制过程各种别扭难用反人类，甚至还需要开发/维护用例脚本、每个用例都写一大堆代码频繁部署等；\u003cbr /\u003e\n**UIGO 不需要写任何代码，录制几乎是按和人正常操作完全一样的方式，操作简单易用，录制回放快、准、稳！**\u003cbr /\u003e\n\u003cbr /\u003e\n2.它们很难兼容各种不同宽高比分辨率屏幕，720P, 1080P 等 16:9 屏幕录制最多只能较好地在 16:9 屏幕回放，\u003cbr /\u003e即便手写代码或图像比对等也很难在列表项 View id/图标 重复控件精准定位，经常点错位置导致大量回放失败；\u003cbr /\u003e\n**UIGO 则能很好地支持 16:9, 19.5:9 等各种不同屏幕录制，然后在 720P, 1080P, 2K, 1080X2340, 1440X3200 \u003cbr /\u003e等各种 不同机型、不同系统、不同屏幕 基本都能很好地精准回放，偏差基本仅在相当于一根头发丝的 3 像素内！**\u003cbr /\u003e\n\u003cbr /\u003e\n3.它们要到处人为设置/调整操作步骤等待时间，还总是要么等太久、要么还没返回就过早执行下一步导致出错，\u003cbr /\u003e因为几乎无法保证网络请求在精准时间内返回，所以总是界面没加载完就滑动、弹窗没显示就点了\"确定\"位置等；\u003cbr /\u003e\n**UIGO 则会自动精准等待 App 发送的各种 HTTP API 网络请求，偏差基本在 2 毫秒内，比眨眼一次还要快 50 倍，\u003cbr /\u003e像专业的测试工程师一样精准高效地等待数据和 UI 都加载好并执行 点击、长按、滑动、缩放 等每一步对应操作！**\u003cbr /\u003e\n\u003cbr /\u003e\n\n### 原理说明\n被测项目不需要写任何用例脚本代码(逻辑代码、注解代码、配置代码等全都不要)，\u003cbr /\u003e\nUIGO 会自动录制 UI 触屏操作、虚拟+实体按键操作、HTTP API 网络请求与响应、\u003cbr /\u003e\nActivity, Fragment, Dialog, PopupWindow 等各种组件(控件)元素的生命周期 等，\u003cbr /\u003e\n回放时根据录制触摸点所在被分割球划分的 上、下、左、右、居中、等比 等区域\u003cbr /\u003e\n以及 屏幕分辨率、状态栏高度、导航栏高度、键盘高度 等来自动计算出回放触摸点，\u003cbr /\u003e\n再加上 id(如果有) 相同且距离最近的 View 区域来辅助微调，高度精准回放触屏操作！\u003cbr /\u003e\n对 返回按键、键盘按键 甚至 输入框编辑过程的每个变化的字符 也都能精准无误地还原！\u003cbr /\u003e\n\n\u003cbr /\u003e\n\n### 示例项目\n[UIGO Android 简单测试 App](https://github.com/TommyLemon/UIGO/tree/master/UIAuto-Android)    直接 [下载](https://github.com/TommyLemon/UIGO/releases/download/0.9.0/UIAuto.apk) （第一次可能失败，返回报错 JSON，一般重试一次就可以）\u003cbr /\u003e\n[UIGO Android 复杂客户端 App](https://github.com/TommyLemon/UIGO/tree/master/APIJSONApp)    直接 [下载](https://github.com/TommyLemon/UIGO/releases/download/0.9.0/UIGO-release.apk) （第一次可能失败，返回报错 JSON，一般重试一次就可以）\n\n#### 安装 App 必须授权 显示悬浮窗、读写文件存储 这两个权限\n其它申请的权限也尽可能都勾选授权，如果不能提前授权，则在使用时弹出是否申请权限弹窗后再确认授权 \u003cbr /\u003e\nhttps://github.com/TommyLemon/APIAuto/issues/61#issuecomment-1997047600\n\n\u003cbr /\u003e\n\n#### 早期零代码单机录制不同分辨率双机同时回放视频\nhttps://www.bilibili.com/video/BV1CK4218788 \u003cbr /\u003e\n\u003cimg width=\"1280\" src=\"https://github.com/TommyLemon/UIGO/assets/5738175/3bb97384-72d9-4b45-ab2c-b0916291ef9f\" href=\"https://www.bilibili.com/video/BV1CK4218788\" /\u003e\n\n#### 早期管理端网页工具零代码远程控制手机录制回放视频\nhttps://www.bilibili.com/video/BV1wA4m137ha\n\u003cimg width=\"1280\" src=\"https://github.com/TommyLemon/UIGO/assets/5738175/e50d00a1-22e8-4908-9d88-579a178965f1\" href=\"https://www.bilibili.com/video/BV1wA4m137ha\" /\u003e\n\n#### 早期仿微信朋友圈复杂 App 录制回放，弹窗、输入、网页、滑动、点击等\nhttps://www.bilibili.com/video/BV1fH4y1E7gD\n\u003cimg width=\"1280\" src=\"https://github.com/TommyLemon/UIGO/assets/5738175/bed421fa-f1a9-47ea-a265-e34853b2d1c8\" href=\"https://www.bilibili.com/video/BV1fH4y1E7gD\" /\u003e\n\n#### 零代码录制回放 H5 移动端网页输入、滑动、点击等操作\nhttps://www.bilibili.com/video/BV1TK421C7y4\n\u003cimg width=\"1280\" src=\"https://github.com/TommyLemon/UIGO/assets/5738175/5c29bec6-2e21-4230-907c-f4ccb1faa4ef\" href=\"https://www.bilibili.com/video/BV1TK421C7y4\" /\u003e\n\n\n### 录制用例\n1.按业务 App 提供的方式打开 UIAuto 管理首页，例如 APIJSONApp 是登录后点击首页标题，UIAuto-Android 是点击首页 [自动 UI 测试] 按钮 \u003cbr /\u003e\n\n2.点击 Record 录制按钮 \u003e 点击顶部悬浮长条中间的 Record 录制 按钮开始录制 \u003e 正常操作 App \u003e 完成一个用例过程后，点击半透明圆形 〇 悬浮球完成录制 \u003cbr /\u003e\n\n3.(可选)点击右下角 post 按钮上传录制的操作和数据等到后端数据库，可先编辑底部的后端服务器 HTTP URL Host 地址为你自己部署的 APIJSON 后端服务 \u003cbr /\u003e\n\n#### 录制注意事项\n**1.按贴靠方式调整分割球位置及贴靠方式** \u003cbr /\u003e\n按下(MotionEvent.ACTION_DOWN 事件)对应 View 的屏幕 \\[X, Y\\] 坐标位置前，必须先完成这步(如果已经配置正确则跳过) \u003cbr /\u003e\n\n**分割球对应横纵两条分割线把屏幕分成了 左上、右上、左下、右下 4 个区域，对应数学上按坐标轴划分的 第 二、一、三、四 象限；** \u003cbr /\u003e\n点击顶部控制条左上角 # 按钮可切换单双分割球，相比单分割球可更精细地设置高级属性 \u003cbr /\u003e\n\n**双分割球中间会出现一个长方形触控区域，默认点击位置按居中处理**，可点击切换 center 居中, ratio 等比, top 靠上, bottom 靠下, left 靠左, right 靠右；\u003cbr /\u003e\n分割球本身贴靠方式可以点击分割球来切换 top_left 左上, top_right 右上, bottom_left 左下, bottom_right 右下, ratio 等比, \u003cbr /\u003e\nratio_top 靠上并垂直纵向等比, ratio_bottom 靠下并垂直纵向等比, ratio_left 靠左并水平横向等比, ratio_right 靠右并水平横向等比 \u003cbr /\u003e\n\n**2.滑动要该快则快、该慢则慢** \u003cbr /\u003e\n**分页列表/网格等滑动尽量快速到底，保证不同宽高比分辨率屏幕上都能在同侧(↓ 从上往下、↑ 从下往上、→ 从左往右、← 从右往左)上显示一致；** \u003cbr /\u003e\n**点按内部 View 前可缓慢滑动保证目标出现在屏幕内，且手离开屏幕前先在同一位置稳住别动，保证不继续自动滚动(不同机型/系统对惯性滚动处理不一致导致偏差)** \u003cbr /\u003e\n\n**3.触控的 View 尽量都有 id，且尽量不要改动** \u003cbr /\u003e\nUIGO 会对有 id 的被触控 View 在回放时进行微调触控位置(不改变 UI 布局，仅微调触屏输入坐标位置)，灵活适配不同屏幕尤其是不同品牌机型的 UI 差异 \u003cbr /\u003e\n\n**4.最好开启托管服务器代理来录制 HTTP API 接口请求与响应流量，用于回放操作时同时回放数据** \u003cbr /\u003e\n保证回放到某个步骤和录制到同一步骤时布局一致，不会触控点按错位\u003cbr /\u003e\n\n**5.不要跳出 App，例如跳转外部浏览器或微信、支付宝等其它 App 来上网、登录、分享、支付等** \u003cbr /\u003e\n目前不支持跨 App 录制回放，当前 App 外的对应事件录制不到也回放不了，打算后续支持对接支持跨 App 录制回放/自动化测试 的项目，\u003cbr /\u003e\n目前碰到这个问题要么避开，要么等待或手动点 》按钮跳过等待来直接继续执行下一步 \u003cbr /\u003e\n\n\u003cbr /\u003e\n\n### 回放用例\n1.参考 录制用例 1 来打开 UIAuto 管理首页 \u003e 点击左下角 Remote 共享列表 按钮 \u003e 点击打开其中一个和 App 及账号对应的用例，或者 录制用例 后直接进入用例详情界面 \u003cbr /\u003e\n\n2.点击用例详情界面左下角 Replay 回放按钮，返回到用例对应开始录制的业务 App 界面，保证状态一致(都是刚进入后没有操作的界面，或者分页列表都下拉刷新过等) \u003cbr /\u003e\n\n3.点击顶部悬浮长条中间的 Replay 回放 按钮开始回放，观察每步操作前后，App 的 UI 展示、界面数据、界面跳转、弹窗显示、键盘输入等是否符合预期(和录制时表现一样) \u003cbr /\u003e\n\n#### 回放注意事项\n**1.回放开始时 App 初始状态必须和录制时一致** \u003cbr /\u003e\n包括所在页面(最好都在首页)、列表/网格滚动距离(最好都是没滚动的初始值 0)、中英文等语言设置、字体大小和样式设置、缓存/调试等自定义配置 等 \u003cbr /\u003e\n\n**2.系统的中英文等语言、字体大小和样式 等设置尽可能保持一致** \u003cbr /\u003e\n\n**3.最好开启托管服务器代理来回放录制时的 HTTP API 接口请求与响应流量数据** \u003cbr /\u003e\n\n\u003cbr /\u003e\n\n### 快速上手\n\n可先跳过这个步骤，先下载体验 App 安装包，安装后 按以下 录制用例、回放用例 文档来操作\n\n#### 集成到被测项目 Android 客户端 App\n##### 1.依赖 UnitAuto-Apk\n把 [UnitAuto-Apk](https://github.com/TommyLemon/UIGO/tree/master/APIJSONApp/UnitAuto-Apk) 导入到你项目 [app moudule 所在目录](https://github.com/TommyLemon/UIGO/tree/master/UIAuto-Android)，[settings.gradle](https://github.com/TommyLemon/UIGO/tree/master/APIJSONApp/settings.gradle) 中\n```groovy\ninclude ':UnitAuto-Apk'\n```\n[app moudule 目录](https://github.com/TommyLemon/UIGO/tree/master/APIJSONApp/app)，[build.gradle](https://github.com/TommyLemon/UIGO/tree/master/APIJSONApp/app/build.gradle) 中\n```groovy\ndependencies {\n    api project(':UnitAuto-Apk')\n}\n```\n\u003cbr /\u003e\n\n##### 2.依赖 UIAuto\n把 [UIAuto](https://github.com/TommyLemon/UIGO/tree/master/APIJSONApp/UIAuto) 导入到你项目 [app moudule 所在目录](https://github.com/TommyLemon/UIGO/tree/master/APIJSONApp)，[settings.gradle](https://github.com/TommyLemon/UIGO/tree/master/APIJSONApp/settings.gradle) 中\n```groovy\ninclude ':UIAuto'\n```\n[app moudule 目录](https://github.com/TommyLemon/UIGO/tree/master/APIJSONApp/app)，[build.gradle](https://github.com/TommyLemon/UIGO/tree/master/APIJSONApp/app/build.gradle) 中\n```groovy\ndependencies {\n    api project(':UIAuto')\n}\n```\n\u003cbr /\u003e\n\n##### 2.初始化 UIAuto\n在 [Application onCreate 方法](https://github.com/TommyLemon/UIGO/blob/master/APIJSONApp/app/src/main/java/apijson/demo/application/DemoApplication.java) 中初始化\n```java\n    @Override\n    public void onCreate() {\n        super.onCreate();\n        UIAutoApp.STEP_TIMEOUT = 30*1000; // 一般为 HTTP API 网络请求超时时间 ms 毫秒值\n        UIAutoApp.getInstance().initUIAuto(this);\n    }\n```\n\u003cbr /\u003e\n\n##### 3.提供 UIAuto 管理界面入口\n在 [AndroidManifest.xml](https://github.com/TommyLemon/UIGO/blob/master/APIJSONApp/app/src/main/AndroidManifest.xml) 中注册 [UIAutoActivity](https://github.com/TommyLemon/UIGO/blob/master/APIJSONApp/UIAuto/src/main/java/uiauto/UIAutoActivity.java)\n```xml\n\u003cmanifest ... \u003e\n    \u003capplication ... \u003e\n      \n        \u003cactivity\n            android:name=\"uiauto.UIAutoActivity\"\n            android:label=\"@string/ui\"\n            android:windowSoftInputMode=\"adjustPan\"\n            android:configChanges=\"orientation|screenSize\"\n            android:screenOrientation=\"portrait\"\n            /\u003e\n        \u003cactivity\n            android:name=\"uiauto.UIAutoListActivity\"\n            android:label=\"@string/ui\"\n            android:windowSoftInputMode=\"adjustPan\"\n            android:screenOrientation=\"portrait\"\n            /\u003e\n\n        \u003cactivity\n            android:name=\"unitauto.apk.UnitAutoActivity\"\n            android:label=\"@string/unit\"\n            android:windowSoftInputMode=\"adjustPan\"\n            android:configChanges=\"orientation|screenSize\"\n            android:screenOrientation=\"userLandscape\"\n            /\u003e\n      \n     \u003c/application\u003e\n\u003c/manifest\u003e\n```\n\n可在你项目的任何界面新增一个按钮或其它形式的入口，仅 DEBUG 模式下展示\n```xml\n    \u003cButton\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:onClick=\"onClickUI\"\n        android:text=\"UIAutoActivity\"\n        android:textAllCaps=\"false\"\n        /\u003e\n```\n参考 [layout/main_tab_activity](https://github.com/TommyLemon/UIGO/blob/master/APIJSONApp/app/src/main/res/layout/main_tab_activity.xml) \u003cbr /\u003e\n\u003cbr /\u003e\n点击这个入口跳转到 [UIAutoActivity](https://github.com/TommyLemon/UIGO/blob/master/APIJSONApp/UIAuto/src/main/java/uiauto/UIAutoActivity.java)\n```java\n    public void onClickUI(View v) {\n        startActivity(UIAutoActivity.createIntent(this));\n    }\n```\n参考 [MainTabActivity](https://github.com/TommyLemon/UIGO/blob/master/APIJSONApp/app/src/main/java/apijson/demo/activity_fragment/MainTabActivity.java) \u003cbr /\u003e\n\u003cbr /\u003e\n\n##### 4.通知 HTTP API 请求与相应\n在 HTTP API 发起请求处加上\n```java\n\t\tUIAutoApp.getInstance().post(new Runnable() {\n\t\t\t@Override\n\t\t\tpublic void run() {\n\t\t\t\tUIAutoApp.getInstance().onHTTPEvent(\n\t\t\t\t\taction, type, method, host, url, headerStr, reqBodyStr, null, activity, fragment\n\t\t\t\t);\n\t\t\t}\n\t\t});\n```\n参考：\u003cbr /\u003e\nhttps://github.com/TommyLemon/UIGO/blob/master/APIJSONApp/app/src/main/java/apijson/demo/manager/HttpManager.java#L137-L147\n\n\n在 HTTP API 响应结果处加上\n```java\n\t\tUIAutoApp.getInstance().post(new Runnable() {\n\t\t\t@Override\n\t\t\tpublic void run() {\n\t\t\t\tUIAutoApp.getInstance().onHTTPEvent(\n\t\t\t\t\t- action, responseCode, method, host, url, headerStr, reqBodyStr, resBodyStr, null, activity, fragment\n\t\t\t\t);\n\t\t\t}\n\t\t});\n```\n参考：\u003cbr /\u003e\nhttps://github.com/TommyLemon/UIGO/blob/master/APIJSONApp/app/src/main/java/apijson/demo/manager/HttpManager.java#L168-L179\n\n\u003cbr /\u003e\n\n##### 5.通知 Dialog, PopupWindow 显示和隐藏\n**业务代码中如果使用了 android.app.AlertDialog，且录制回放用例涉及**，则可以换成 uiauto.AlertDialog， \u003cbr /\u003e\n最简单的方式是顶部菜单 Edit \u003e Find \u003e Replace in files 全局搜索 import android.app.AlertDialog， \u003cbr /\u003e\n然后点搜索弹窗右下角 Replace All 按钮批量改为 import uiauto.AlertDialog。 \u003cbr /\u003e\n如果因为用了自定义或第三方通用 Base Alert Dialog 不方便替换，则可以 extends uiauto.AlertDialog 或在里面加上：\n\n```java\n\t@Override\n\tpublic void show() {\n\t\tsuper.show();\n\t\tUIAutoApp.getInstance().onUIAutoDialogShow(this); // 通知已显示\n\t}\n\n\t// 拦截隐藏事件监听\n\tprivate OnDismissListener listener;\n\t@Override\n\tpublic void setOnDismissListener(OnDismissListener listener) {\n\t\tthis.listener = listener;\n\t}\n\n\tprivate Activity context;\n\tprivate void init(Context ctx) {\n\t\tthis.context = (Activity) ctx;\n\n\t\tsuper.setOnDismissListener(new OnDismissListener() {\n\t\t\t@Override\n\t\t\tpublic void onDismiss(DialogInterface dialog) {\n\t\t\t\tif (listener != null) {\n\t\t\t\t\tlistener.onDismiss(dialog);\n\t\t\t\t}\n\n\t\t\t\tUIAutoApp.getInstance().onUIAutoDialogDismiss(Dialog.this); // 通知已隐藏\n\t\t\t}\n\t\t});\n\t}\n\n\t// 每个可重写的构造方法都保证调用到 init 方法\n\tpublic AlertDialog(Context context) {\n\t\tsuper(context);\n\t\tinit(context);\n\t}\n\n\tpublic AlertDialog(Context context, @StyleRes int themeResId) {\n\t\tsuper(context, themeResId);\n\t\tinit(context);\n\t}\n\n\tpublic AlertDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {\n\t\tsuper(context, cancelable, cancelListener);\n\t\tinit(context);\n\t}\n\n```\n\n**所有 Dialog, DatePickerDialog, TimePickerDialog, ProgressDialog, CharacterPickerDialog 等也同上处理。** \u003cbr /\u003e\n\n\u003cbr /\u003e\n\n**业务代码中如果使用了 android.widget.PopupWindow，且录制回放用例涉及**，则可以换成 uiauto.PopupWindow， \u003cbr /\u003e\n最简单的方式是顶部菜单 Edit \u003e Find \u003e Replace in files 全局搜索 import android.widget.PopupWindow， \u003cbr /\u003e\n然后点搜索弹窗右下角 Replace All 按钮批量改为 import uiauto.PopupWindow。 \u003cbr /\u003e\n如果因为用了自定义或第三方通用 Base Popup Window 不方便替换，则可以 extends uiauto.PopupWindow 或在里面加上：\n\n```java\n    private android.widget.PopupWindow popupWindow;\n    private View view;\n\n    @Override\n    public void showAsDropDown(View anchor, int xoff, int yoff, int gravity) {\n        super.showAsDropDown(anchor, xoff, yoff, gravity);\n\n        if (view == null) {\n            try {\n                Field field = android.widget.ListPopupWindow.class.getDeclaredField(\"mPopup\");\n                field.setAccessible(true);\n                popupWindow = (android.widget.PopupWindow) field.get(this);\n                //  popupWindow.setOutsideTouchable(false);\n\n                Field dvField = android.widget.PopupWindow.class.getDeclaredField(\"mDecorView\");\n                dvField.setAccessible(true);\n                view = (View) dvField.get(popupWindow);\n\n                if (view == null) {\n                    View cv = popupWindow.getContentView();\n                    view = cv == null ? null : cv.getRootView();\n                }\n            } catch (Throwable e) {\n                e.printStackTrace();\n            }\n        }\n\n        if (view == null) {\n            View cv = getContentView();\n            view = cv == null ? null : cv.getRootView();\n        }\n\n        Window w = getWindow();\n\n        // 通知已显示\n        UIAutoApp app = UIAutoApp.getInstance();\n        app.onUIAutoWindowCreate(w.getCallback(), w);\n        app.setCurrentPopupWindow(popupWindow, view, null, context, null);\n    }\n\n\n    // 拦截隐藏事件监听\n    private android.widget.PopupWindow.OnDismissListener listener;\n    @Override\n    public void setOnDismissListener(android.widget.PopupWindow.OnDismissListener listener) {\n        this.listener = listener;\n    }\n\n    public Window getWindow() {\n        Activity ctx = view == null ? null : (Activity) view.getContext();\n        if (ctx == null) {\n            ctx = context;\n        }\n        return ctx.getWindow();\n    }\n\n    private Activity context;\n    private void init(Context ctx) {\n        this.context = (Activity) ctx;\n\n        super.setOnDismissListener(new android.widget.PopupWindow.OnDismissListener() {\n            @Override\n            public void onDismiss() {\n                if (listener != null) {\n                    listener.onDismiss();\n                }\n\n                Window w = getWindow();\n\n                // 通知已隐藏\n                UIAutoApp app = UIAutoApp.getInstance();\n                app.onUIAutoWindowDestroy(w.getCallback(), w);\n                app.setCurrentPopupWindow(null, null, null, context, null);\n            }\n        });\n    }\n\n    // 每个可重写的构造方法都保证调用到 init 方法\n    public PopupWindow(Context context) {\n        super(context);\n        init(context);\n    }\n\n    public PopupWindow(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        init(context);\n    }\n\n    public PopupWindow(Context context, AttributeSet attrs, @AttrRes int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        init(context);\n    }\n\n    public PopupWindow(Context context, AttributeSet attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {\n        super(context, attrs, defStyleAttr, defStyleRes);\n        init(context);\n    }\n\n    public PopupWindow(Context context, View contentView) {\n        super(contentView);\n        init(context);\n    }\n\n    public PopupWindow(Context context, int width, int height) {\n        super(width, height);\n        init(context);\n    }\n\n    public PopupWindow(Context context, View contentView, int width, int height) {\n        super(contentView, width, height);\n        init(context);\n    }\n\n    public PopupWindow(Context context, View contentView, int width, int height, boolean focusable) {\n        super(contentView, width, height, focusable);\n        init(context);\n    }\n\n```\n\n**所有 ListPopupWindow 等也同上处理。** \u003cbr /\u003e\n\u003cbr /\u003e\n\n#### Java 后端 Server\n可先跳过，使用 http://apijson.cn:8080 或 http://apijson.cn:9090 代替 \u003cbr /\u003e\n\n见 APIJSON-Demo 后端上手 \u003cbr /\u003e\nhttps://github.com/APIJSON/APIJSON-Demo?tab=readme-ov-file#1%E5%90%8E%E7%AB%AF%E4%B8%8A%E6%89%8B\n\n\u003cbr /\u003e\n\n### 录制、回放用例\n见以上 [录制用例](https://github.com/TommyLemon/UIGO/tree/master?tab=readme-ov-file#%E5%BD%95%E5%88%B6%E7%94%A8%E4%BE%8B)、[回放用例](https://github.com/TommyLemon/UIGO/tree/master?tab=readme-ov-file#%E5%9B%9E%E6%94%BE%E7%94%A8%E4%BE%8B) 的说明。\n\n\u003cbr /\u003e\u003cbr /\u003e\n\n### 常见问题\n#### 1.apijson.cn 访问不了\n托管服务地址改为 http://47.98.196.224:8080  \u003cbr /\u003e\nhttps://github.com/TommyLemon/APIAuto/issues/13\n \n\n\u003cbr /\u003e\n  \n更多常见问题 \u003cbr /\u003e\nhttps://github.com/TommyLemon/APIAuto/issues\n\n\u003cbr /\u003e\n\n\n### 技术交流\n##### 关于作者\n[https://github.com/TommyLemon](https://github.com/TommyLemon)\u003cbr /\u003e\n\u003cimg width=\"1280\" src=\"https://github.com/TommyLemon/UIGO/assets/5738175/ec77df98-ff9b-43aa-b2f1-2fce2549d276\"\u003e\n\n如果有什么问题或建议可以 [去 APIAuto 提 issue](https://github.com/TommyLemon/APIAuto/issues)，交流技术，分享经验。\u003cbr \u003e\n如果你解决了某些 bug，或者新增了一些功能，欢迎 [提 PR 贡献代码](https://github.com/Tencent/APIJSON/blob/master/CONTRIBUTING.md)，感激不尽。\n\u003cbr /\u003e\n\u003cbr /\u003e\n\n### 其它项目\n\n[APIJSON](https://github.com/Tencent/APIJSON) 🚀 腾讯零代码、全功能、强安全 ORM 库 🏆 后端接口和文档零代码，前端(客户端) 定制返回 JSON 的数据和结构\n\n[APIAuto](https://github.com/TommyLemon/APIAuto) 敏捷开发最强大易用的 HTTP 接口工具，机器学习零代码测试、生成代码与静态检查、生成文档与光标悬浮注释，集 文档、测试、Mock、调试、管理 于一体的一站式体验\n\n[UnitAuto](https://github.com/TommyLemon/UnitAuto) 机器学习零代码单元测试平台，零代码、全方位、自动化 测试 方法/函数 的正确性、可用性和性能\n\n[SQLAuto](https://github.com/TommyLemon/SQLAuto) 智能零代码自动化测试 SQL 语句执行结果的数据库工具，任意增删改查、任意 SQL 模板变量、一键批量生成参数组合、快速构造大量测试数据\n\n[Android-ZBLibrary](https://github.com/TommyLemon/Android-ZBLibrary) Android MVP 快速开发框架，Demo 全面，注释详细，使用简单，代码严谨\n\n\n### 持续更新\nhttps://github.com/TommyLemon/UIGO/commits/master\n\n### 我要赞赏\nUIGO 从私有仓库默默开发了 3 年多到现在终于开源了，Apache 证书对商用和非商用都很友好。\u003cbr /\u003e\n创作不易、坚持更难，右上角点亮 ⭐ Star 支持/收藏下本项目吧，谢谢 ^_^ \u003cbr /\u003e\nhttps://github.com/TommyLemon/UIGO\n\u003cbr /\u003e\n\u003cbr /\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftommylemon%2Fuigo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftommylemon%2Fuigo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftommylemon%2Fuigo/lists"}