CLI·데스크탑 앱
pm suspend로만 멈춥니다. 대상은 OPPO·Honor·Xiaomi·vivo의 중국 내수용(国行) ROM이며 화면 문구가 중국어로 하드코딩돼 있습니다.이 저장소는 폰 설정 앱의 스위치를 대신 누르는 자동화 엔진(tool/fast.py)과, 기종별 클릭 경로(recipes/), 그리고 AI 에이전트용 작업 규칙서(AGENTS.md)로 이루어져 있습니다. 같은 엔진을 GUI(pywebview) 데스크톱 앱으로도 감싸 Mac·Windows 설치 파일로 배포합니다.
처리 대상은 README의 표 기준으로 시스템 광고 개인화·OAID 추적, 검색창 핫 키워드와 피드, 앱스토어 추천 배너, 앱별 마케팅 알림 채널, 광고 컴포넌트(com.opos.ads, com.miui.systemAdSolution), 그리고 광고 링크(hap://)가 열어 주는 “쾌응용(快应用)” 프레임워크입니다.
사람이 하면 “설정 → 개인정보 → 광고 → 개인화 끄기”를 앱마다 반복해야 합니다. 이 도구는 화면의 글자와 스위치 위치를 읽고, 미리 적어 둔 경로(레시피)대로 눌러 줍니다.
중요한 점은 이 비서가 “위험한 일은 하지 않는다”는 약속이 대부분 문서(규칙서)에 있고 코드가 강제하는 범위는 좁다는 것입니다. 3~4장에서 그 경계를 코드로 확인합니다.
| 방식 | 누가 실행하나 | 필요한 것 |
|---|---|---|
| ① AI 에이전트 | Claude Code 등이 AGENTS.md를 읽고 명령 실행 | PC, 케이블, 명령 실행 가능한 AI 도구 |
| ② 채팅 AI | 사람이 폰을 직접 누르고, AI는 안내만 | prompts/의 프롬프트 |
| ③ 수동 체크리스트 | 사람 | docs/清单/ 브랜드별 목록 |
| ④ 데스크톱 클라이언트 | GUI 앱이 같은 CLI를 자식 프로세스로 실행 | Mac(Apple/Intel) 또는 Windows 10/11 |
핵심 설계는 “화면을 읽어 스위치를 찾는 엔진 한 벌”을 CLI, AI 에이전트, GUI가 모두 재사용한다는 점입니다. 어느 경로로 쓰든 결국 tool/run.py와 tool/fast.py가 실행됩니다.
레시피는 PNM-AN10(Honor), PLP120(OPPO), M154FF(Xiaomi)처럼 중국 내수 모델 번호에 묶여 있고, 클릭 대상은 “隐私”, “广告”, “设置” 같은 중국어 UI 문자열입니다. 이 글은 도구 사용법보다 UI 자동화를 어떻게 설계했는지를 배우는 데 초점을 둡니다.
초판 관측으로, GitHub API 기준(2026-10-25 조회) 스타 264개, 포크 27개이고 저장소는 2026-10-24에 만들어졌습니다. 커밋 25개가 전부 하루 안에 올라와 있으며 릴리스는 v0.1.0, v0.2.0입니다. 즉 오래 검증된 프로젝트가 아니라 막 공개된 초기 프로젝트입니다.
CLAUDE.md, AGENTS.md, CODEBUDDY.md가 모두 있습니다..github/workflows/build-windows.yml이 v* 태그에서 PyInstaller 빌드, 스모크 테스트, Inno Setup 설치 파일, 포터블 zip을 만듭니다. Mac은 gui/build_mac.sh에 서명·공증 옵션이 있습니다(README는 서명·공증을 주장하지만 이 분석에서는 배포 바이너리를 검증하지 않았습니다).pm disable-user 금지, 약관 동의 금지, 계정 화면 캡처 금지, 되돌리기 명령 제공.| 접근 | 방식 | 이 프로젝트와의 차이 |
|---|---|---|
| 수동 설정 | 사람이 앱마다 설정 열기 | 같은 경로를 레시피로 기록해 4분 안팎에 반복(README: Honor 레시피 재실행 4분) |
패키지 삭제·비활성화(pm uninstall, disable-user) | 시스템 앱 제거 | 이 프로젝트는 쓰지 않음. 기능 고장과 복구 곤란을 피하려고 pm suspend만 사용 |
| 루팅·모듈 | system 파티션 수정 | 루팅 없음, 시스템 업데이트 영향 없음을 목표로 함 |
| DNS·네트워크 차단 | 광고 도메인 차단 | 네트워크는 건드리지 않고 앱 설정 스위치를 끔(샤오미 msa는 예외 메모 있음) |
다만 “광고가 실제로 얼마나 줄었는지”를 측정한 자료는 저장소에 없습니다. README의 효과 서술은 작성자의 실측 표(기종별 ✅/⚠️/❌)이며 독립 검증은 아닙니다.
다음 규모 수치는 초판 3341d60 관측값입니다. GitHub 언어 통계는 Python 90,572바이트, HTML 50,166, Shell 2,931, Inno Setup 1,507입니다. 파이썬 중 핵심 로직은 tool/ 4개 파일(합 1,027줄), gui/app.py 403줄, 레시피 3개(합 502줄)입니다. 추적 파일은 74개이며 이미지 25개, 문서 20여 개가 큰 비중을 차지합니다.
| 계층 | 기술 | 근거 파일 |
|---|---|---|
| 기기 제어 | adb, uiautomator2(요구 >=3.0) | requirements.txt, tool/fast.py |
| 화면 읽기 | dump_hierarchy()가 돌려주는 XML을 xml.etree로 파싱 | Phone.tree() |
| 클릭·스크롤 | input swipe, input motionevent 셸 명령 | Phone.click(), scroll() |
| 상태 확인 | dumpsys, pm, settings | tool/run.py, chan_fast.py |
| 기종 스크립트 | 파이썬 exec()로 실행하는 레시피 | recipes/*/recipe.py |
| 데스크톱 UI | pywebview + 단일 HTML(394줄) | gui/app.py, gui/web/index.html |
| 패키징 | PyInstaller, Inno Setup, zsh 스크립트 | gui/windows.spec, installer.iss, build_mac.sh |
| 배포 CI | GitHub Actions(windows-latest, Python 3.12) | build-windows.yml |
requirements.txt는 한 줄(uiautomator2==3.7.1)입니다. 나머지는 표준 라이브러리(subprocess, re, glob, xml.etree)입니다. GUI 패키징 때만 pywebview, pyinstaller, pillow가 추가됩니다(워크플로의 pip install 줄).
GUI는 adb가 없으면 Google의 platform-tools를 내려받습니다. 최신 소스에는 사용자가 미리보기에서 확인한 오류 로그를 유지보수자의 서버로 보내는 report_payload()·send_report()도 추가됐습니다. 따라서 네트워크 요청이 adb 다운로드 하나뿐이라는 이전 설명은 더 이상 맞지 않습니다. 이 전송 기능은 2026-10-27 v0.2.5로 출시됐습니다. README 다운로드와 gui/app.py의 VERSION도 0.2.5로 바뀌었습니다.
run.py: 명령 분배와 안전 목록모든 하위 명령은 run.py -s <시리얼> <명령> 형태입니다. -s를 빼면 종료합니다(“命令格式…”). 컴퓨터에 TV나 에뮬레이터가 같이 연결돼 있어도 엉뚱한 기기를 건드리지 않게 하려는 장치입니다.
코드가 직접 강제하는 안전 규칙은 NEVER 집합입니다.
# tool/run.py
NEVER = {"com.heytap.quicksearchbox", "com.coloros.assistantscreen", "com.android.systemui",
"com.vivo.systemuiplugin", "com.heytap.market", "com.xiaomi.market", "com.hihonor.appmarket"}
elif cmd == "suspend":
bad = [p for p in rest if p in NEVER]
if bad:
sys.exit(f"这些包挂了会坏功能,不挂:{bad}")
...
sh(s, f"pm suspend --user 0 {p}")
if suspended(s, p): f.write(p + "\n") # 되돌리기용 기록
검색창, 왼쪽 위젯 화면, 앱스토어, 시스템 UI는 정지시키면 기능이 깨지기 때문에 코드에서 거부합니다. 정지된 패키지는 backups/<모델>-<시각>/suspended.txt에 기록되고, unsuspend가 이 파일을 읽어 되돌립니다.
fast.py: Phone 클래스 (화면 읽기 → 판단 → 클릭)핵심은 Phone 클래스입니다. 스크린샷 인식이 아니라 접근성 트리(XML)를 읽기 때문에 한 번에 약 0.03~0.1초(주석 기준)로 빠릅니다.
| 메서드 | 역할 |
|---|---|
tree(), texts() | 현재 화면 XML을 받아 글자·좌표를 추출. 상태바(com.android.systemui) 글자는 제외 |
switches() | 스위치 노드를 찾아 (제목, 켜짐 여부, 중심 좌표) 목록 생성 |
tap(text) | 글자를 찾아 클릭. 안 보이면 스크롤, 끝까지 가도 없으면 맨 위로 돌아가 한 번 더 |
off(keep, only) | 화면의 켜진 스위치를 끔. only는 제목에 해당 단어가 있는 것만, keep은 해당 단어가 있으면 보존 |
dismiss(), confirm() | 방해 팝업은 거절 쪽 버튼으로, 스위치 끈 뒤 확인창은 확인 쪽 버튼으로 처리 |
setting(kw) | 시스템 설정의 검색창에서 키워드를 검색해 결과로 이동 |
start(pkg) | 앱을 실행하고 첫 화면의 팝업을 정리 |
스위치를 찾는 로직(switches())은 두 갈래입니다. 표준 위젯은 checkable="true" 속성으로 찾고, resource-id에 switch가 들어 있으나 접근성 정보가 없는 직접 그린 스위치는 화면 캡처에서 트랙 색의 채도를 봅니다.
# tool/fast.py
@staticmethod
def _pixel_on(img, l, t, r, b):
"""开关轨道取几个点:彩色(蓝/绿/橙,饱和度高)=开,灰白=关。"""
img = img.convert("RGB")
sat = 0
for fx in (0.25, 0.5, 0.75):
R, G, B = img.getpixel((int(l + (r - l) * fx), (t + b) // 2))
sat = max(sat, max(R, G, B) - min(R, G, B))
return sat > 60 # 채도 60 초과 = 켜짐
click()은 input tap 대신 input swipe x y x y 80(제자리에서 80ms 누름)을 씁니다. AGENTS.md의 “알려진 함정” 표에 “일부 앱이 input tap을 무시한다”고 적혀 있습니다. scroll()은 input motionevent DOWN → MOVE×6 → sleep 0.12 → UP 순서로 관성을 없애 “정한 만큼만” 움직이게 하고, 제목줄·하단바를 피하려고 화면 22~80% 구간만 드래그합니다.
exec()로 실행하는 미니 DSL# fast.py 의 run 명령 (요약)
g = {"p": p, "__name__": "__recipe__", "ONLY": rest[1:]}
src = open(rest[0], encoding="utf-8").read()
build = p.d.shell("getprop ro.build.display.id").output.strip()
m = re.search(r'^BUILD\s*=\s*"([^"]+)"', src, re.M)
if m and not build.startswith(m.group(1)):
print(f"⚠ 机型脚本是按 {m.group(1)} 录的,这台是 {build}:页面可能对不上 ...")
exec(src, g)
레시피 파일에는 import 없이 전역 p(Phone)가 이미 있습니다. @step("이름") 데코레이터가 단계를 정의하고, 데코레이터 안에서 곧바로 실행합니다. 화면이 잠겨 있으면 이후 단계를 모두 건너뛰고, 단계 안에서 예외가 나도 다음 단계로 넘어갑니다. 아래는 샤오미 레시피의 일부입니다.
# recipes/xiaomi-M154FF/recipe.py
BUILD = "OS4.0"
@step("系统广告")
def _():
p.setting("个性化广告推荐", "个性化广告推荐", box="搜索")
p.off(only=["个性化广告推荐"], page="系统·广告服务")
@step("应用商店")
def _():
p.start("com.xiaomi.market")
p.go("我的", "设置")
gear() # 글자 없는 톱니바퀴 아이콘 찾기
if p.tap("隐私", exact=False):
p.off(only=["个性化服务"], page="商店·隐私"); p.back()
초판 3341d60에서 읽은 레시피는 Honor 13단계, OPPO 9단계, Xiaomi 8단계였습니다. 최신 기종 범위는 뒤의 개정 절을 따릅니다. 레시피의 only=[...] 목록은 “무엇을 끌지”의 화이트리스트이고, keep=[...]는 보존 목록입니다. 이 목록이 사실상 안전 규칙입니다.
miss 카운터화면 경로가 맞지 않을 때를 위해 Phone.miss가 있습니다. 한 단계에서 대상을 한 번 못 찾으면 이후에는 스크롤하며 찾지 않고 현재 화면만 확인한 뒤 “快速放弃(빠른 포기)”합니다. 버전이 다른 기기에서 수 분을 허비하지 않고 못 찾은 단계를 빠르게 넘기기 위한 설계입니다.
dumpsys notification 파싱chan_fast.py는 dumpsys notification --noredact 출력에서 정규식으로 AppSettings와 NotificationChannel{mId=..., mName=...}를 읽습니다. 채널 이름이 KW 정규식(营销·活动·推荐·资讯·福利 등)에 맞고 SKIP(下载·订单·物流·支付·验证·来电·天气预警 등)에 걸리지 않으면 후보로 출력합니다. 끌 때는 am start -a android.settings.CHANNEL_NOTIFICATION_SETTINGS --es ...APP_PACKAGE ... --es ...CHANNEL_ID ...로 채널 설정 화면을 직접 열고 첫 스위치(“알림 허용”)를 누른 뒤 상태를 다시 읽어 확인합니다. 후보 목록은 사람이 channels.tsv에서 검토한 후 chan-off에 넣게 되어 있습니다.
gui/app.py의 Api 클래스는 JS에서 호출되는 메서드(devices, status, chan_scan, start, poll, stop, restore, dev_off, diagnostics)를 노출하고, 내부에서 run.py와 chan_fast.py를 자식 프로세스로 실행해 출력을 줄 단위로 UI에 전달합니다. 패키징 후에는 파이썬이 따로 없으므로 "본 프로그램 --cli 스크립트명 인자…" 방식(cli_main의 runpy.run_path)으로 같은 스크립트를 실행합니다. GUI에서만 서비스성 채널(SERVICE 정규식: 핫스팟·긴급 알림·도난 방지·운전 모드·라이브 등)을 기본 선택에서 뺍니다.
finish와 dev-offbackup은 “충전 중 화면 켜짐(stay_on_while_plugged_in)” 원래 값을 저장하고, 레시피 실행 전에 이 값을 7로 바꿔 작업 중 화면이 꺼지지 않게 합니다. finish가 원래 값으로 복구하고 개발자 모드 해제를 안내합니다. dev-off --yes는 adb_wifi_enabled, development_settings_enabled, adb_enabled를 0으로 써서 연결을 끊습니다.
이전 개정에서 0.2.3 이후의 미발행 기능으로 설명했던 읽기 충돌 처리·보호 알림·OnePlus 적응은 CHANGELOG에서 0.2.4 수록으로 바뀌었습니다. 다음 내용은 최신 고정 소스와 0.2.4 배포 경계를 함께 읽어야 합니다.
ui_session.py가 시리얼의 해시로 같은 PC·같은 폰의 동시 읽기 프로세스를 막습니다. POSIX flock·Windows 바이트 잠금을 쓰며 파일은 지우지 않습니다. 실패·종료 때 이번 실행이 시작한 adb 연결/서비스만 정리하고 재사용한 외부 서비스는 멈추지 않습니다. 이미 등록됨 오류에만 한 번 재시도합니다.chan_fast.py의 ShellPhone은 알림 스캔·상태 재검사 때 UiAutomation을 띄우지 않고 adb만 읽습니다. 실제 전환은 채널 제목·설정 Activity·명확한 알림 스위치를 모두 확인해야 합니다. GUI는 첫 읽기 연결 충돌 뒤 나머지 읽기 의존 단계를 skipped로 남기고 실패를 성공으로 바꾸지 않습니다.channel_policy.py는 촬영 위치 찾기·추천 기능의 채널명·ID·옛 목록 설명까지 검사합니다. 스캔·GUI 선택·클릭 직전에도 적용해 낡은 목록으로 다시 끄는 일을 막습니다. 이미 꺼진 것을 자동으로 켜지는 않으며, 사용자가 명시한 단일 채널 복구는 별도입니다.fast.py는 매번 화면 크기를 갱신하고, 클릭 뒤 스위치가 사라지면 옛 좌표를 재사용하지 않습니다. 같은 브랜드의 참고 레시피는 AAC_REF 안전 모드에서 이름이 지정되지 않은 일반 스위치를 일괄 끄지 않습니다. 빌드는 명시한 리소스 목록만 포함해 로컬 로그·백업을 제외합니다. 이번 해설은 소스 대조이며 폰 연결·설치·회귀 테스트 실행은 하지 않았습니다.
이전 README의 다운로드는 v0.2.5였습니다. 고정 소스 674364254323a59d0b7dd2632100a73cc494270f와 CHANGELOG는 기존 미발행 오류 로그 전송이 0.2.5에 수록됐음을 확인해 줍니다. 0.2.4의 기기별 수정은 유지됩니다. 배포 바이너리를 실행하거나 서명·기기 동작을 독립 검증한 것은 아닙니다.
chan_fast.py는 ColorOS·Honor·Huawei의 별도 설정 Activity, 삼성의 헤더·content-desc, Honor의 행 안 스위치를 구분합니다. vivo는 앱 전체 화면에서 채널 화면으로 들어간 기록과 서로 다른 제목을 요구합니다. 제목이 앱 이름과 같으면 건너뜁니다. Huawei·일부 Honor·삼성 경로는 개발자의 실기기 검증이 끝났다는 뜻이 아닙니다.adb_link.py는 연결 오류를 구분하고 최대 15초 기다려 한 번 재시도합니다. 계속 끊겨 있으면 해당 단계를 실패로 끝냅니다. fast.py는 Xiaomi 입력 권한 거부를 사전 탐지하며, 알림 전환 중에는 충전 시 화면 켜짐 값을 저장·복원합니다.학습 과제: side_effects()에서 허용 목록 밖 채널 변화와 앱 전체 변화가 각각 어떤 중단 경로로 이어지는지 표로 만드세요. 오류 보고 미리보기에는 없는 설치 UUID가 전송 단계에서 추가된다는 점도 report_payload()와 send_report()를 비교해 확인할 수 있습니다.
현재 README의 다운로드는 v0.2.6입니다. tool/run.py::wait_unlocked는 화면을 깨운 뒤 소유자가 잠금을 풀 때까지 최대 90초 기다립니다. 자동 잠금 해제 기능이 아니며, 시간이 지나면 해당 단계를 실행하지 않았다고 종료합니다.
adb_link.py::keyguard_showing은 잠금 필드와 알림창 포커스를 함께 확인해 ColorOS 계열의 잠금을 구분합니다. ui_session.py::DeviceLock은 앞 단계의 읽기 프로세스가 종료될 때까지 최대 20초 기다린 뒤 점유 오류를 냅니다.chan_fast.py는 시스템이 잠근 회색 알림 스위치를 건너뛰며, Huawei 계열 목록 행은 클릭 가능한 조상을 끝없이 찾는 대신 목록의 직접 자식까지 찾습니다. 이는 소스상의 대응이며 모든 기기의 동작을 보장하지 않습니다.REFERENCE 매핑으로 고정해 커뮤니티 기종이 추가될 때 다른 기기의 기본 선택이 바뀌지 않게 했습니다. Xiaomi의 msa 네트워크 차단 인터페이스가 없는 경우에는 앱 중지 결과와 차단 미지원 안내를 구분합니다.AGENTS.md — 도구가 지켜야 할 규칙과 “알려진 함정” 표.tool/run.py — 명령 목록과 NEVER, quickapps(), backup.tool/fast.py의 Phone — 가장 배울 것이 많은 파일.recipes/xiaomi-M154FF/recipe.py — 가장 짧은 레시피.docs/04-给新机型写脚本.md — 레시피 작성 규칙.gui/app.py — 자식 프로세스 + 실시간 로그 패턴.이 저장소의 .gitignore는 backups/를 제외합니다. 백업에는 설치된 앱 목록과 알림 원문이 담길 수 있어 공개 저장소에 올라가지 않게 한 구성입니다(6장 주의 참고).
해상도·폴더블 여부가 달라도 “隐私”라는 글자를 찾아 그 위치를 누르면 동작합니다. 대신 글자가 바뀌면 깨집니다. 그래서 BUILD 접두사로 레시피가 만들어진 시스템 버전을 확인하고, 불일치하면 경고만 하고 계속 진행합니다(실패한 단계는 건너뜀).
off()는 각 화면에서 첫 스위치를 누르고 팝업 또는 화면 이동을 확인한 뒤, 문제가 없으면 나머지를 연속으로 누르고 마지막에 switches()를 다시 읽어 아직 켜진 것을 재시도합니다. 끝내 안 꺼진 항목은 “✗ 关不掉”로 표시합니다. 자동화에서 “눌렀다”와 “바뀌었다”를 구분하는 방법입니다.
코드 주석에 따르면 ColorOS는 스위치 옆에 “关闭” 상태 텍스트가 있어, 이를 확인 버튼으로 오인해 누르면 스위치가 다시 켜집니다. 그래서 confirm()은 클래스 이름에 Button이 들어간 노드만 누릅니다. 이런 “실제 기기에서 겪은 사례”가 AGENTS.md의 함정 표(10건)에 정리돼 있습니다.
pm suspend 전에 대상과 결과를 suspended.txt에 기록하고, unsuspend가 이 기록으로 되돌림.channels.tsv로 끄고 chan-on으로 복원.backup은 시스템·사용자 앱 목록, settings list, 알림 상태 전체를 저장.check(읽기) → backup → recipe → chan-scan(읽기) → 사람이 목록 편집 → chan-off(끝에 “仍开着: N 个” 재검사) → quickapp(읽기) → 사용자 동의 후 suspend. 위험한 단계 앞에 읽기 전용 단계를 배치한 점이 AI 에이전트와 함께 쓰는 도구 설계로 참고할 만합니다.
AGENTS.md는 10개의 “하드 규칙”(모든 adb 명령에 -s, 앱 삭제 금지, 약관 동의 금지, 계정 화면 캡처 금지 등)을 둡니다. 현재 코드는 -s·NEVER 외에도 기기별 읽기 세션 잠금, 채널 페이지 신원·제목 검증과 보호 채널 제외를 강제합니다. 다만 변경 동의처럼 문서에 의존하는 경계도 남아 있습니다. 예를 들어 fast.py off 명령은 only 없이 호출하면 일반 스위치는 끄지만 광고 추적 제한처럼 반대 의미의 보호 스위치는 켜고, 의미를 판정하지 못한 부정형은 건드리지 않습니다. AI 에이전트용 도구를 만들 때는 “문서로 부탁하는 규칙”과 “코드가 막는 규칙”을 구분해 두는 편이 안전합니다.
backup 명령은 dumpsys notification --noredact 결과를 notif.txt로, 설치된 앱 목록을 sys.txt·user.txt로 저장합니다. GUI의 피드백 기능은 시리얼을 치환하고 앱 목록·알림 내용을 첨부하지 않는다고 설명하지만, 로컬 backups/ 폴더 자체는 민감 정보를 담을 수 있으니 공유하거나 커밋하지 마세요.
| 항목 | 요구 사항 | 근거 |
|---|---|---|
| 컴퓨터 | macOS, Windows, Linux(CLI). 데스크톱 앱은 Mac(Apple 칩/Intel), Windows 10/11 | docs/01, README 다운로드 표 |
| Python | 3.9 이상(문서), CI 빌드는 3.12 | docs/01, build-windows.yml |
| 패키지 | uiautomator2==3.7.1 | requirements.txt |
| adb | platform-tools. GUI는 없으면 Google에서 내려받음 | docs/01, gui/app.py |
| 케이블 | 데이터 전송이 되는 USB 케이블 | docs/01 |
| 폰 | 개발자 옵션 + USB 디버깅 켬, 컴퓨터 인증(“항상 허용”), 잠금 해제 상태 | AGENTS.md §3, run.py check |
| 대상 기기 | OPPO/OnePlus/realme, Honor, Xiaomi/Redmi, vivo의 중국 내수 ROM | AD_PKGS, QUICKAPP, README 표 |
| Windows GUI | Edge WebView2 런타임(없으면 안내 대화상자) | gui/app.py 끝부분 |
fold_open()이 화면 비율(0.8 초과)로 경고합니다.OnePlus 적응과 읽기 충돌·기능 알림 보호는 0.2.4에 수록됐습니다. CHANGELOG는 ColorOS 17·MagicOS 10·OriginOS 6의 특정 실기기 결과와, Huawei·일부 Honor·삼성의 제보 기반 변경을 구분합니다. 브랜드 전체 지원으로 일반화하지 마세요. 현재 레시피는 기종별로 나뉘며, 같은 브랜드의 참고 스크립트와 전용 스크립트를 구분해야 합니다.
실습할 때도 처음에는 읽기 전용 명령(devices, check, quickapp, chan-scan, fast.py ls/scan)만 쓰세요. 스위치를 바꾸거나 패키지를 정지시키는 명령(recipe, chan-off, suspend, quickapp off, fast.py off/only)은 공기계나 백업이 있는 기기에서만 사용하세요. 이 도구는 중국 내수 ROM용이라 다른 ROM에서 어떻게 동작할지 보장되지 않습니다.
run.py의 cmd == "..." 분기를 모두 찾아 명령 이름과 호출하는 함수(sh, py, quickapps 등)를 표로 정리하고, “읽기 전용 / 상태를 바꿈”으로 분류하세요. 13개 명령 중 어느 것이 사람 동의를 요구하도록 문서에 적혀 있는지 AGENTS.md와 대조합니다.
chan_fast.py의 KW와 SKIP 정규식을 일부만 옮겨 새 파이썬 파일에서 테스트하세요(chan_fast를 import하면 uiautomator2가 필요합니다. 아래 단어 목록은 원본의 일부입니다).
import re
KW = re.compile(r"营销|活动|推荐|资讯|福利|优惠|红包|直播|会员|recommend|promo|news", re.I)
SKIP = re.compile(r"订单|物流|快递|支付|验证|来电|消息|提醒|天气预警|系统|红包助手", re.I)
samples = ["内容与营销", "活动优惠", "天气预警", "红包助手", "订单提醒", "直播提醒"]
for s in samples:
print(s, "후보" if KW.search(s) and not SKIP.search(s) else "제외")
# 질문: "红包助手"가 제외되어야 하는 이유와 최신 SKIP·protected_channel의 차이는 무엇인가? (AGENTS.md §5 의 '삭제할 서비스 채널' 표와 비교)
공기계에 USB 디버깅을 켜고 아래 명령만 실행해 출력 구조를 읽어 보세요. 상태를 바꾸는 명령은 아닙니다.
pip3 install -r requirements.txt
python3 tool/run.py devices # 시리얼, 모델, 레시피 유무
python3 tool/run.py -s <시리얼> check # 잠금 여부, 레시피 버전 일치, 광고 패키지 상태
python3 tool/run.py -s <시리얼> quickapp # 快应用 컴포넌트 검사 (off 를 붙이지 않음)
python3 tool/fast.py -s <시리얼> ls # 현재 화면의 글자와 스위치 상태 목록
fast.py ls의 출력과 폰 화면을 나란히 놓고 “접근성 트리가 어떤 글자를 보여 주는가”를 관찰하세요.
recipes/xiaomi-M154FF/recipe.py의 8개 단계에 각각 “무엇을 끄는지 / 무엇을 남기는지 / 막힐 때 어떻게 되는지”를 주석으로 달아 보세요. 그리고 docs/04-给新机型写脚本.md를 보며 explore.py(스위치를 켜고 끄지 않는 탐색)가 레시피 작성을 어떻게 돕는지 설명해 봅니다.
fast.py off가 only 없이 호출되는 경우를 막는 방법을 설계하세요. 예를 들어 CLI 레벨에서 --yes-all이 없으면 거부하거나, 끌 스위치 제목을 먼저 출력하고 확인을 받는 드라이런(dry-run) 모드를 추가합니다. 설계 문서와 테스트 시나리오를 먼저 쓰고, 구현은 별도 브랜치에서 하세요.
| 주차 | 주제 | 할 일 |
|---|---|---|
| 1주 | adb 기본기 | adb devices, adb shell getprop, settings get/put, dumpsys 출력 읽기(모두 조회 위주) |
| 2주 | 안드로이드 UI 계층 | uiautomator dump 결과의 bounds, checkable, resource-id 이해. Phone.switches() 다시 읽기 |
| 3주 | uiautomator2 API | d.dump_hierarchy(), d.shell(), d.screenshot() 사용법을 공식 문서로 정리 |
| 4주 | 패키지 관리 명령 | pm list packages, pm suspend/unsuspend와 disable-user의 차이, 사용자(--user 0) 개념 |
| 5주 | 배포 패키징 | pywebview JS API 브리지, PyInstaller spec, GitHub Actions 윈도우 빌드, 코드 서명·공증 개념 |
더 나아가 접근성 서비스 API, 알림 채널(NotificationChannel) 구조, MCP/에이전트용 도구 설계(안전 규칙을 코드로 옮기는 방법)를 이어서 공부하면 좋습니다.
| 용어 | 쉬운 설명 | 이 저장소에서 만나는 곳 |
|---|---|---|
| adb | PC에서 폰에 명령을 보내는 공식 도구 | run.py의 adb_bin(), sh() |
| uiautomator2 | 파이썬으로 안드로이드 UI를 읽고 제어하는 라이브러리 | import uiautomator2 as u2 |
| 접근성 트리 | 화면 요소를 구조화한 XML | Phone.tree() |
| OAID | 광고 추적용 익명 기기 식별자(중국 안드로이드) | README “广告跟踪(OAID)” |
| pm suspend | 앱을 삭제하지 않고 일시 정지(아이콘 회색, 실행 불가). 되돌릴 수 있음 | suspend, unsuspend |
| pm disable-user | 앱 비활성화. 이 프로젝트는 쓰지 않음 | AGENTS.md 하드 규칙 3 |
| 快应用(쾌응용) | 설치 없이 열리는 제조사 연합 “경량 앱”. 광고가 hap:// 링크로 연다 | QUICKAPP 목록, docs/07 |
| 알림 채널 | 앱 알림을 종류별로 나눈 안드로이드 설정 단위 | chan_fast.py |
| 레시피(机型脚本) | 기종별 클릭 경로를 적은 파이썬 파일 | recipes/*/recipe.py |
| dumpsys | 시스템 서비스의 내부 상태를 텍스트로 출력 | 알림, 키가드(잠금), 사용 기록 |
| 국행(国行) | 중국 내수용으로 출시된 기기·ROM | README, AGENTS.md |
| ColorOS / MagicOS / HyperOS / OriginOS | OPPO / Honor / Xiaomi / vivo의 안드로이드 기반 OS 이름 | docs/清单/ |
| pywebview | 웹 화면(HTML)을 데스크톱 창에 담는 파이썬 라이브러리 | gui/app.py |
| PyInstaller | 파이썬 프로그램을 실행 파일로 묶는 도구 | gui/windows.spec |
| 스모크 테스트 | 빌드 결과가 최소한 켜지는지 보는 가벼운 검사 | gui/smoke_test.py |
| 드라이런 | 실제로 바꾸지 않고 바뀔 내용만 보여 주는 실행 | (새 안전 모드와는 별개 개념, 과제 5) |
2026-10-28 재검토 소스: 674364254323a59d0b7dd2632100a73cc494270f. 설치·외부 모델 호출·실행 없이 아래 파일을 대조했습니다.
README.md · CHANGELOG.md · tool/adb_link.py · tool/chan_fast.py · tool/fast.py · gui/app.py · gui/build_mac.sh
0.2.5 오류 로그 전송: 미리보기·동의·제한·보관 정책
shell pm, 무선 디버깅중국어 문서가 대부분이라 번역기를 쓰되, 클릭 대상 문자열은 원문 그대로 확인하세요. 초판은 3341d60이며, 이전 2026-10-26 개정은 e2419d182ae8637ef3c9359c45effb3e80e5a8f7의 README·CHANGELOG·requirements·ui_session.py·chan_fast.py·fast.py·channel_policy.py·troubleshooting.py·gui/app.py를 기준으로 했고, 설치·실행은 하지 않고 소스를 읽어 정리했습니다.
| 항목 | 내용 | 기준 |
|---|---|---|
| 저장소 | rddmwmddr/android-ad-cleaner | GitHub |
| 선정 위치 | TrendShift #16 | 2026-10-25 분석 큐 |
| 스타 / 포크 | 264 / 27 | GitHub API, 2026-10-25 |
| 생성일 / 최근 push | 2026-10-24 / 2026-10-24 | GitHub API |
| 릴리스 | v0.2.6 (README와 CHANGELOG 기준) | 2026-10-28 고정 소스 |
| 언어(바이트) | Python 90,572 · HTML 50,166 · Shell 2,931 · Inno Setup 1,507 | GitHub 언어 통계 |
| 추적 파일 | 74개, 커밋 25개 | 커밋 3341d60 |
| 라이선스 | MIT (저작권 표기 “2026”) | LICENSE |
초기 프로젝트입니다. 초판의 공개 직후 관측과 0.2.4의 제한된 실기기 결과를 구분해야 합니다. 지원 범위는 모델·OS·단계별로 다릅니다. 이 분석은 소스 읽기만 했고 실제 폰에서 실행한 결과가 아닙니다.
배포 바이너리는 확인하지 않았습니다. README의 Mac 서명·공증, Windows 설치 파일 내용은 소스와 별개입니다. 실행 파일보다 소스로 실행하는 편이 검증하기 쉽습니다.
되돌림은 일부입니다. 문서의 되돌리기 표에 따르면 앱 내부 스위치는 수동으로 다시 켜야 하고, 시스템 업데이트로 값이 초기화될 수 있습니다.
에이전트에 맡길 때의 권한. adb 접근 권한을 가진 AI에게 규칙서만으로 안전을 기대하지 말고, 처음에는 읽기 전용 명령 중심으로 진행하며 변경 전 목록을 직접 검토하세요.