Agent Skills › n0an/VivaDicta › analyze-unrecognized-apps

analyze-unrecognized-apps

GitHub

从 Google Analytics 拉取未识别应用 Bundle ID,比对映射表并补充 URL Scheme 及返回地址映射。

.agents/skills/analyze-unrecognized-apps/SKILL.md n0an/VivaDicta

Trigger Scenarios

需要分析或添加新的 App URL Scheme 映射 查询未识别应用的归属或返回链接配置

Install

npx skills add n0an/VivaDicta --skill analyze-unrecognized-apps -g -y
More Options

Non-standard path

npx skills add https://github.com/n0an/VivaDicta/tree/main/.agents/skills/analyze-unrecognized-apps -g -y

Use without installing

npx skills use n0an/VivaDicta@analyze-unrecognized-apps

指定 Agent (Claude Code)

npx skills add n0an/VivaDicta --skill analyze-unrecognized-apps -a claude-code -g -y

安装 repo 全部 skill

npx skills add n0an/VivaDicta --all -g -y

预览 repo 内 skill

npx skills add n0an/VivaDicta --list

SKILL.md

Frontmatter
{
    "name": "analyze-unrecognized-apps",
    "description": "Pull unrecognized host app bundle IDs from Google Analytics via gog, diff them against the mapping tables and add URL scheme mappings",
    "disable-model-invocation": true
}

Analyze Unrecognized Host Apps

Last run: 2026-09-27 (second pass) - cleared the 35 single-event bundle IDs left over from the first pass, plus Bear, which arrived since. Added 24 return-URL mappings (9 schemes read from the app's own source or the simulator runtime, 5 AASA-confirmed universal links, 10 under the weaker block) and 12 knownNoSchemeHosts entries. The script now reports "nothing new" at the default settings. Also rewrote the Prerequisites: the documented gog auth add --services analytics command both narrows the token and is refused by Google because of stale YouTube grants on gog's OAuth client, so the remote flow with include_granted_scopes stripped is the working recipe. Findings worth keeping: ru.yandex.mobile.search is Yandex Browser, not the Yandex app (ru.yandex.mobile); X Chat and QuickPaste have no way back at all; Brave and Firefox also claim http/https, so map only brave:// / firefox://; Apple's Translate and Image Playground are only localization stubs in the iOS 27 simulator runtime, so their schemes cannot be read there.

Previous run 2026-09-27 (first pass) - first run on the gog pipeline (scripts/unrecognized_host_apps.py, 28-day window, 132 bundle IDs / 528 events, 29 rows with two or more events). Added 17 return-URL mappings and 12 knownNoSchemeHosts entries; after the edit the script reports "nothing new" at --min-events 2. Twelve mappings are AASA-confirmed at the root or a catch-all path, five went in under a weaker block (AASA matches only a specific page, or the scheme comes from vendor docs). Identity checks via itunes.apple.com/lookup?bundleId= paid off: co.anysphere.sand is Grok Bot by X, not Cursor (its x.ai AASA matches only concrete share ids, so noScheme); com.jiangjia.gif is Kuaishou; com.supersethealth.superset is now Bevel; ru.yandex.uber now belongs to Fasten. VK's main client went in as https://vk.com/feed, not vk://, because several VK apps share the team. com.apple.Preferences went to noScheme: its only route is the private App-prefs://. The 34 single-event bundle IDs were left for a later batch. Previous run 2026-09-12 (19 mappings, 16 noScheme) established: the AASA is often the fastest primary source even for apps that do have a scheme; an app's build manifest beats its Info.plist when the scheme is a build variable; Telegram forks must never be mapped to tg://; share extensions go to noScheme, editor extensions whose content lives in the parent app are aliased to it.

You are given the following context: $ARGUMENTS

Task

Pull the unrecognized_host_app bundle IDs from Google Analytics, work out which ones need a return URL, and add the mappings to the app.

Prerequisites (one-time)

The data comes from the GA4 Analytics Data API through the gog CLI (brew install gog if missing). The stored gog token for anton.novoselov@gmail.com must carry the analytics.readonly scope; the default services do not include it. Check with gog auth list -p: the services column must include analytics. The Mac token has had it since 2026-09-27, so this is only needed after a token reset.

Do not run a bare gog auth add ... --services analytics --force-consent. It fails in two ways:

  • --services replaces the token's service set, so passing only analytics would leave a token with nothing else. Always pass the full current list from gog auth list -p, plus analytics.
  • gog's OAuth client once received YouTube grants, and gog adds include_granted_scopes=true to every consent URL. Google merges those old grants into the request and refuses it: "Access blocked: Authorization Error ... scopes that cannot be requested together (youtube.force-ssl, drive.file, youtube, ...)", Error 400 invalid_request.

What works is the remote flow, with that flag stripped from the URL:

SERVICES=appscript,calendar,chat,classroom,contacts,docs,drive,forms,gmail,people,sheets,slides,tasks,analytics   # current list + analytics
# 1. print the consent URL, drop the scope-merge flag, open it
gog auth add anton.novoselov@gmail.com --services $SERVICES --force-consent --remote --step 1 \
  | awk -F'\t' '/^auth_url/{print $2}' | sed 's/&include_granted_scopes=true//' | xargs open
# 2. approve; the browser lands on an unreachable http://127.0.0.1:<port>/oauth2/callback?... page. That is expected.
#    Copy that full URL, then exchange it (within ~5 minutes of step 1):
gog auth add anton.novoselov@gmail.com --services $SERVICES --force-consent --remote --step 2 --auth-url '<callback URL>'

An agent can run both steps itself: step 1, hand the user the link, then run step 2 with the callback URL they paste back.

Verify:

gog ga report "$(cat internal/ga_property_id)" --dimensions eventName --metrics eventCount --from 7daysAgo --max 2 -p

A 403 insufficientPermissions means the scope is still missing; the script points back to this section. The GA4 property ID (the property behind the Firebase project vivadicta) is private: it lives in the gitignored internal/ga_property_id, which the script reads ($GA_PROPERTY_ID overrides it). The account ID, the Explore report URL and the OAuth client details are in internal/firebase-analytics-events.md. On a fresh clone, create internal/ga_property_id first. The event is unrecognized_host_app, the bundle ID lives in the custom event dimension bundle_id (registered 2026-02-24; older hits show as (not set)).

Instructions

  1. Read the current mappings from VivaDicta/VivaDictaApp.swift — find the knownURLs dictionary inside returnURL(forHostId:). The knownNoSchemeHosts set lives just above it, in attemptReturnToHost(hostId:).

  2. Pull and diff the analytics data with the repo script, which runs gog ga report, filters the event client-side (the CLI has no filter flag) and compares every bundle ID against both tables in the local Swift file:

    scripts/unrecognized_host_apps.py                  # last 28 days, actionable rows only
    scripts/unrecognized_host_apps.py --days 90 --all  # longer window, include mapped/noScheme rows
    scripts/unrecognized_host_apps.py --json /tmp/unrecognized.json   # machine-readable copy
    

    The default window is 28 days, which is what the weekly run wants: old app versions keep reporting apps that are already mapped, and the script hides those. Exit code 3 means nothing actionable - stop and say so. Use --min-events 2 to skip singletons when the list is long; singletons still deserve a look when they are obviously popular apps.

    Fallback only if the API is unavailable: the user can paste a screenshot or list from the GA Explore exploration "Unrecognized Host Apps" (URL in internal/firebase-analytics-events.md; also reachable from Firebase Console → Analytics → "View more in Google Analytics"). Then do the cross-reference from step 3 by hand.

  3. Review the script's categories — it prints one of these per bundle ID; check the automatic verdicts rather than re-deriving them:

    mapped — already in knownURLs (hidden unless --all; it shows up from app versions that predate the mapping)

    noscheme — already in knownNoSchemeHosts (hidden unless --all)

    variant:<id> — same app as a mapped <id> under a different bundle ID: a team-ID prefix (4GU63N96WE.com.p5sys.jumpdesktop), a regional build (com.amazon.AmazonDE), or an app extension (net.whatsapp.WhatsApp.ShareExtension). Aliasing a prefixed or regional build to the same URL is safe. An extension is a judgement call — returning to the parent app is not the surface the user was in. The script only detects prefix/suffix variants; spot regional builds (AmazonUK vs Amazon) yourself.

    apple-new — com.apple.* not in either table. Usually a system service that cannot be returned to (com.apple.SafariViewService, com.apple.springboard, com.apple.siri) and belongs in knownNoSchemeHosts; some Apple apps do have schemes (shortcuts://, mobilenotes://, maps://), check the simulator runtime binary before deciding.

    new — real third-party app not yet in either table. These are the research queue.

    not-actionable — (not set), pre-custom-dimension data. Ignore.

  4. Research a way back for each new app. Search for:

    • "[app name] iOS URL scheme"
    • "[app name] deep link"
    • "[bundle id] URL scheme"
    • Known URL scheme databases and GitHub repos

    Two sources beat any blog list, and are worth the extra step for high-volume apps:

    • The app's own registration — its open-source Info.plist or build file (CFBundleURLSchemes), or, for Apple apps, the binary in a simulator runtime under /Library/Developer/CoreSimulator/.../RuntimeRoot/Applications/.
    • The app's AASA file — https://<domain>/.well-known/apple-app-site-association. If it lists the bundle ID, the matching https:// URL is a valid fallback for an app that registers no custom scheme. This works only on this code path, because the lookup runs solely for the app the keyboard was just typing into, so it is installed by definition.

    Watch for schemes shared between apps. Swiftgram registers tg:// and telegram:// alongside official Telegram; iOS picks between claimants unpredictably, so map only a scheme the app owns outright (sg://).

  5. Output a summary table with:

    • Bundle ID
    • Event count
    • Category (mapped / variant / apple-new / new / not actionable)
    • Return URL (if found), confidence level and the source it came from
  6. After user confirms which entries to add, update VivaDicta/VivaDictaApp.swift:

    • Apps with a way back → the knownURLs dictionary in returnURL(forHostId:)
    • Apps with none → the knownNoSchemeHosts set, so they stop being reported as unrecognized

    Re-run scripts/unrecognized_host_apps.py afterwards: every row you handled must now come back as mapped or noscheme (visible with --all), which also proves the Swift edit parses.

    There is no plist step, and adding one is a regression. LSApplicationQueriesSchemes was deleted on 2026-08-29 along with the canOpenURL gate it existed to permit. Apple caps that array at 50 entries, and past the cap canOpenURL returns false whether or not the app is installed — which silently killed the newest mappings. UIApplication.open needs no declaration and reports failure through its own result, so the table can now grow without limit. Do not reintroduce either.

  7. Update the "Last run" line at the top of this file with the date and what changed.

- Do NOT add URL schemes you are not confident about without user confirmation - Low-confidence schemes should be flagged — the most reliable verification is the app's own `CFBundleURLSchemes`, from its source, its shipped binary, or an installed copy - Some bundle IDs (Apple system services, embedded browser views) are not actionable and should be called out as such - Treat the event counts as a floor, not a census. `.unrecognizedHostApp` only fires when the keyboard resolves a host bundle ID, so any period where resolution was broken under-reports every app at once - The script reads the tables from the working tree, so run it on the branch you are about to edit; a parse failure ("could not parse knownURLs / knownNoSchemeHosts") means the Swift declarations moved or were renamed - fix the regexes in `scripts/unrecognized_host_apps.py`, do not fall back to screenshots

Version History

  • 39bda25 Current 2026-09-28 02:29

    优化了 Prerequisites 中的 OAuth 授权流程说明,修复了因 YouTube 权限导致的令牌获取失败问题。

  • 7fc71f2 2026-09-22 15:01

    2026-09-12 版本新增 19 个返回 URL 映射和 16 个 knownNoSchemeHosts 条目。主要改进包括利用 AASA 作为快速确认源,以及从构建清单(而非 Info.plist)中解析由构建变量定义的 Scheme。同时明确了系统服务(如 Siri)和扩展应用的分类处理逻辑。

  • fbbdfe0 2026-09-09 09:12

    新增29个应用返回URL映射及11个无方案主机记录;更新了AASA查找技巧和Bundle ID识别经验。

  • 888131c 2026-09-03 10:21

    更新代码读取位置至 VivaDictaApp.swift,移除过时的 canOpenURL 检查及 LSApplicationQueriesSchemes 限制,新增对 App Info.plist 和 AASA 文件的深度研究方法。

  • c5601d4 2026-07-25 08:14

Same Skill Collection

.agents/skills/app-container-group/SKILL.md
.agents/skills/app-container/SKILL.md
.agents/skills/asc-aso-audit/SKILL.md
.agents/skills/asc-aso-rankings/SKILL.md
.agents/skills/asc-localize-metadata/SKILL.md
.agents/skills/asc-metadata-sync/SKILL.md
.agents/skills/asc-release-flow/SKILL.md
.agents/skills/asc-whats-new-writer/SKILL.md
.agents/skills/axe-simulator-control/SKILL.md
.agents/skills/coverage-report/SKILL.md
.agents/skills/diagram/SKILL.md
.agents/skills/ios-log-capture/SKILL.md
.agents/skills/ios-simulator-skill/SKILL.md
.agents/skills/krankie-audit/SKILL.md
.agents/skills/krankie-rankings/SKILL.md
.agents/skills/loc-report/SKILL.md
.agents/skills/logs-start/SKILL.md
.agents/skills/logs-stop/SKILL.md
.agents/skills/pr/SKILL.md
.agents/skills/prcdx/SKILL.md
.agents/skills/release-prepare/SKILL.md
.agents/skills/screenshot/SKILL.md
.agents/skills/simulator-screenshot-time/SKILL.md
.agents/skills/spm-build-analysis/SKILL.md
.agents/skills/start-logs-device-structured/SKILL.md
.agents/skills/start-logs-device/SKILL.md
.agents/skills/start-logs/SKILL.md
.agents/skills/stop-logs-device-structured/SKILL.md
.agents/skills/stop-logs-device/SKILL.md
.agents/skills/stop-logs/SKILL.md
.agents/skills/swift-concurrency-pro/SKILL.md
.agents/skills/swift-testing-pro/SKILL.md
.agents/skills/swiftdata-pro/SKILL.md
.agents/skills/swiftui-liquid-glass/SKILL.md
.agents/skills/swiftui-performance-audit/SKILL.md
.agents/skills/swiftui-pro/SKILL.md
.agents/skills/xcode-build-benchmark/SKILL.md
.agents/skills/xcode-build-fixer/SKILL.md
.agents/skills/xcode-build-orchestrator/SKILL.md
.agents/skills/xcode-compilation-analyzer/SKILL.md
.agents/skills/xcode-project-analyzer/SKILL.md
.agents/skills/xcodebuild-testing/SKILL.md
.agents/skills/commit-push/SKILL.md

Metadata

Files
0
Version
39bda25
Hash
41b38afa
Indexed
2026-07-25 08:14

ホーム - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-09-30 05:33
浙ICP备14020137号-1