Skip to content

Exmeaning/playfetch

Repository files navigation

playfetch

English | 简体中文

playfetch is a command-line tool for downloading APKs from Google Play zero-config anonymously or using your own credentials. It features reproducible device emulation and official Google Play checksum verification, emitting a complete manifest.json detailing the device identity, package metadata, and hash verification logs for every download.

playfetch pull com.example.app

Features

  • Reproducible Device Profiles: Pin and log exact hardware parameters (SDK level, ABI architecture, screen density DPI, and locale). Because Google Play serves different Split APKs based on hardware capabilities, playfetch ensures all downloads remain deterministically traceable.
  • Google Play Hash Verification: Verifies every downloaded APK against official SHA256 and SHA1 digests returned directly in Google Play's delivery response.
  • Provenance Manifest Generation: Automatically generates a manifest.json alongside downloaded APKs, recording device identity, application metadata, and verification results.
  • Flexible Packaging Modes: Supports uncompressed split APKs (split), single .apks archives (apks), or both (both).
  • Zero-Config Anonymous Retrieval: Fetches temporary credentials on-the-fly via an integrated token dispenser and performs local device checkin without requiring a personal Google account.
  • Multi-Account & Session Management: Supports logging in with custom Google accounts (saving long-lived AAS tokens), multi-region account management, default account assignment, and session caching.
  • CI & Script Friendly: Detects interactive TTY vs piped/CI environments automatically. Emits clean, non-mangling discrete progress updates in CI pipelines with standard stdout/stderr separation and strict exit codes.

Installation

Via Go

go install github.com/Exmeaning/playfetch/cmd/playfetch@latest

Build from Source

git clone https://github.com/Exmeaning/playfetch.git
cd playfetch
go build ./cmd/playfetch

Dependencies: Requires only google.golang.org/protobuf. Generated protobuf bindings and device profiles are vendored; protoc is not required.


Command Reference

Quick Examples

# Inspect the download plan and Play's official hashes without fetching files
playfetch plan com.example.app

# Download APKs and assemble into a single .apks archive
playfetch pull com.example.app -mode apks

# Inspect regional titles using specific locale and timezone
playfetch info com.example.jp -locale ja_JP -tz Asia/Tokyo

# Check for updates and pull only when a newer versionCode is available
playfetch watch com.example.app || playfetch pull com.example.app -mode apks

Commands

Command Description
pull <pkg> Download APKs, verify Play hashes, and write manifest.json (alias: download)
plan <pkg> Resolve download package set and official hashes without fetching bytes
info <pkg> Retrieve live package metadata and version details
search <query> Search package names by keyword
watch <pkg> Compare live versionCode against an existing manifest.json
devices List bundled device profiles
doctor Diagnose service connectivity, DFE headers, and token dispenser health
login Authenticate with a personal Google account and store the AAS token
logout Remove stored account credentials
accounts List saved accounts and active default
interactive Force interactive shell prompt
version Print program version

Exit Codes

  • 0: Success.
  • 1: Execution error.
  • 2: Invalid command-line usage or arguments.
  • 10: (watch only) A newer versionCode is available upstream.

Command-Line Flags

playfetch reorders arguments automatically; flags may be specified before or after the package name:

-profile <name|path> Device profile name (see `devices`) or path to a custom .properties file
-locale  <locale>    Locale sent to Play (e.g. `ja_JP`, `en_US`)
-tz      <timezone>  Timezone (defaults to device profile value)
-sdk     <int>       Override profile SDK version (`Build.VERSION.SDK_INT`)
-abi     <list>      Override profile ABI list (e.g. `arm64-v8a`)
-dpi     <int>       Override profile screen density
-out     <path>      Exact output directory (overrides `-out-root`)
-out-root <path>     Root directory for downloads (default: `./downloads`)
-mode    <mode>      Output mode: `split` (default), `apks`, or `both`
-label   <string>    Custom free-text tag written into `manifest.json`
-vc      <int>       Pin download to a specific `versionCode`
-force               Force re-downloading files even if local verified copies exist
-json                Emit output in JSON format
-v                   Verbose logging mode (logs API requests)
-account <name|email>Specify stored account name, email, or region label
-refresh             Ignore cached session and re-authenticate/re-checkin
-anonymous           Force dispenser anonymous mode (ignores saved accounts)
-accept-tos          Automatically accept Play Terms of Service for new accounts

Directory Structure & Manifest

All downloaded packages are organized under ./downloads/<package_name>/<version_code>/:

downloads/com.example.app/1783590150/
├── base.apk
├── split_config.arm64_v8a.apk
├── split_config.xxhdpi.apk
└── manifest.json

Sample manifest.json

{
  "device": {
    "profile": "px_9a",
    "sdk": 35,
    "abis": ["arm64-v8a"],
    "locale": "en_US"
  },
  "app": {
    "package": "com.example.app",
    "version_code": 1783590150,
    "version_name": "1.0.0"
  },
  "files": [
    {
      "role": "base",
      "name": "base.apk",
      "size": 177690473,
      "play_sha256": "2b80ad54...",
      "play_sha1": "ec39d85a...",
      "local": {
        "sha256": "2b80ad54...",
        "sha1": "ec39d85a...",
        "md5": "71357fcb..."
      },
      "verified": true,
      "verify_note": "matched Play sha256+sha1"
    }
  ]
}

Packaging Modes (-mode)

  • split (default): Preserves original files as served by Google Play (individual base and split APKs).
  • apks: Packs base and split APKs into a single .apks archive (ZIP container readable by SAI or bundletool), removing standalone split files after verification.
  • both: Retains both standalone APKs and the .apks archive.

Note: To produce a single installable universal APK, use bundletool or APKEditor for resource merging and re-signing. playfetch preserves original, unmodified publisher-signed binaries.


Authentication & Accounts

Anonymous Mode (Default)

Zero configuration required. playfetch requests temporary credentials from a token dispenser and performs local device checkin. Suitable for fetching public applications.

Warning

Public Dispenser Notice & Abuse Prevention

The default anonymous credentials rely on a shared public Token Dispenser account pool maintained by Aurora OSS for Aurora Store users (~250 shared accounts, strictly rate-limited by Google).

playfetch does not own or guarantee this public pool. High-frequency automated jobs or CI loops can degrade the pool, trigger Cloudflare blocks, or cause endpoint shutdowns for the entire community.

For CI/CD pipelines, automated scripts, or high-volume downloads, please follow the Self-Hosting Token Dispenser Guide or use dedicated accounts to avoid abusing shared community resources.

Custom Account Sign-In

To download account-restricted or paid titles, sign in with a custom account:

playfetch login

Authentication steps:

  1. Follow the interactive prompt to open the Google Embedded Setup page in a browser.
  2. Obtain the oauth_token Cookie under accounts.google.com via DevTools.
  3. Paste the token into playfetch. The tool exchanges it for a long-lived AAS Token stored with 0600 file permissions.

Direct AAS token input is also supported:

playfetch login -email user@example.com -aas-token <AAS_TOKEN>

Multi-Account Management

Manage multiple accounts and switch between them seamlessly:

# Save an account with a region tag
playfetch login -name jp-account -region JP

# List stored accounts
playfetch accounts

# Set default account
playfetch accounts -set-default jp-account

# Execute command with a specific account
playfetch pull com.example.app -account jp-account

Storefront & Regional Availability

  • Billing-bound Accounts: Storefront country is determined by the account's billing country.
  • Unbound Accounts / Anonymous Mode: Storefront country is determined dynamically by the request's egress IP.
  • Note: info metadata availability does not guarantee pull access. If an application is unavailable in the active storefront region, plan or pull will fail with HTTP 400 (DF-DFERH-01). Use a VPN/proxy or region-matched account to access geo-restricted titles.

Device Emulation

Google Play serves specific APK splits tailored to requesting hardware profiles. playfetch includes 45 bundled device profiles up to Android 15. The default profile is px_9a (Pixel 9a, SDK 35, arm64-v8a only, 420dpi).

Override hardware attributes via flags or specify custom .properties files:

playfetch pull com.example.app -sdk 34 -abi arm64-v8a,armeabi-v7a -dpi 480
# Or use a custom properties file
playfetch pull com.example.app -profile ./my-device.properties

Interactive Shell Mode

Running playfetch without arguments in an interactive TTY launches the interactive shell prompt:

$ playfetch
playfetch v0.1.0 -- reproducible Google Play APK retrieval
  account: anonymous (dispenser)
  device: px_9a (sdk 35, arm64-v8a, 420dpi), locale en_US

playfetch> search bang dream
playfetch> info com.bushiroad.en.bangdreamgbp -locale ja_JP
playfetch> pull com.bushiroad.en.bangdreamgbp -mode apks

The interactive prompt accepts standard commands and flags identically to the CLI. Non-TTY invocations without arguments exit with status code 2.


Troubleshooting (doctor)

Use the doctor command to diagnose service availability, DFE header integrity, and dispenser health:

playfetch doctor

Environment Variables

Core parameters can be overridden via environment variables:

  • PLAYFETCH_DISPENSER: Custom Token Dispenser service URL.
  • PLAYFETCH_CREDENTIALS: Custom account credentials storage path.
  • PLAYFETCH_DOWNLOADS: Root directory for downloads.
  • PLAYFETCH_DFE_TARGETS: Override X-DFE-Encoded-Targets header.
  • PLAYFETCH_DFE_PHENOTYPE: Override X-DFE-Phenotype header.

License & Acknowledgements

  • License: Released under GPL-3.0-or-later.
  • Acknowledgements:
    • Aurora OSS: Protobuf schemas, device profile definitions, and token dispenser architecture.
    • apkeep (EFForg): Device profile references and AAS token authentication flows.
    • Full third-party notices available in THIRD-PARTY.md.

About

Reproducible Google Play APK retrieval tool with device profile pinning & official checksum verification.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages