tweaselORG / meta

(Currently) only used for the issue tracker.
2 stars 0 forks source link

Downloading APKs from Google Play using `googleplay`/`google` or `apkeep` #46

Closed baltpeter closed 2 months ago

baltpeter commented 2 months ago

I just wanted to document how to download APKs using the tool that changes its name, repository, and CLI every few months, since it really wasn't exactly intuitive this time…

Currently, the repo is at: https://github.com/3052/google

Get the source code and build using Go:

git clone git@github.com:3052/google.git
cd google
go build -o gplay ./internal/play

That produces the executable gplay.

Now, to login and a create a device, first go to https://accounts.google.com/embedded/setup/v2/android and log in. Once you click "I agree" on the last page, a cookie called oauth_token will be placed (value starts with oauth2_4/0). The website will continue loading forever, but the cookie is already valid.

Now, run the following.[^mkdir]. You can also create devices for the other architectures and choose which one to use later. You will need to pass the desired architecture through -p with every command related to downloading (see below), otherwise it will default to x86, which is very likely not what you want (and will panic if you haven't set up an x86 device).

[^mkdir]: The current version is very buggy (I'm on 8533cfd). It doesn't create the required directories itself and saves the device definitions in a different directory than where it later expects to read them. This causes various commands to just panic and fail if you don't do the workarounds. I would open an issue and/or fix this myself, but it really doesn't seem like the maintainer wants that, so… shrug

mkdir -p ~/google-play/google-play

./gplay -o "<oauth2_4/0…>"
# This will create an arm64-v8a device. Alternatively, use -p 0 for x86 or -p 1 for armeabi-v7a
./gplay -d -p 2

cp ~/google-play/google-play/*.bin ~/google-play

Now, to download an app, first acquire it (you only need to do this once per app and account, but acquiring an app multiple times doesn't appear to cause problems, either):

./gplay -a <app ID> -acquire -p <platform>

Next, grab the app details:

./gplay -a <app ID> -p <platform>

This will output something like this, copy the version code from here:

msg=POST URL=https://android.googleapis.com/auth
msg=GET URL="https://android.clients.google.com/fdfe/details?doc=com.yopeso.lieferando"
downloads = 14.81 million
files = APK
name = Lieferando.de
offered by = Takeaway.com
price = 0 EUR
requires = 7.0 oder höher
size = 32.74 megabyte (32741614)
updated on = 19.03.2024
version code = 1610000497
version name = 10.26.0

Finally, you can download the app like this. Optionally, pass -s to get a single APK instead of multiple split APKs.

./gplay -a <app ID> -v <version code> -p <platform>
./gplay -a <app ID> -v <version code> -s -p <platform>

Help output for reference, since it isn't in the README anymore:

❯ ./gplay
Usage of ./gplay:
  -a string
        application ID
  -acquire
        acquire application
  -d    checkin and sync device
  -level value
        level (default INFO)
  -o string
        oauth_token from accounts.google.com/embedded/setup/v2/android
  -p value
        map[0:x86 1:armeabi-v7a 2:arm64-v8a]
  -s    single APK
  -v uint
        version code
baltpeter commented 2 months ago

Actually, it might be useful for others that run into these issues if we try to do some SEO by pasting the error messages you will encounter if you don't do the workarounds mentioned above. :D

❯ ./gplay -d
msg=POST URL=https://android.googleapis.com/checkin
panic: open /home/benni/google-play/google-play/x86.bin: no such file or directory

goroutine 1 [running]:
main.main()
    /home/benni/tmp/google/internal/play/main.go:84 +0x6e6

❯ ./gplay -o "oauth2_4/…"
msg=POST URL=https://android.googleapis.com/auth
panic: open /home/benni/google-play/token.txt: no such file or directory

goroutine 1 [running]:
main.main()
    /home/benni/tmp/google/internal/play/main.go:79 +0x6db

❯ ./gplay -a se.maginteractive.quizduel2
msg=POST URL=https://android.googleapis.com/auth
panic: open /home/benni/google-play/x86.bin: no such file or directory

goroutine 1 [running]:
main.main()
    /home/benni/tmp/google/internal/play/main.go:72 +0x6c5

And these were from when I tried to build the executable using the wrong commands:

❯ go build
no Go files in /home/benni/tmp/google

❯ go build play/play.go
# command-line-arguments
./play.go:73:9: undefined: GoogleCheckin
./play.go:82:9: undefined: GoogleAuth
./play.go:86:9: undefined: GoogleCheckin

❯ go run
go: no go files listed

❯ go run play/play.go
package command-line-arguments is not a main package

❯ go get
go: no package to get in current directory

❯ go build ./internal/play
go: downloading 154.pages.dev/log v1.2.0
go: build output "play" already exists and is a directory
baltpeter commented 2 months ago

The CLI changed again

Usage of ./gplay:
  -a    acquire
  -b value
        map[0:x86 1:armeabi-v7a 2:arm64-v8a]
  -d    checkin and sync device
  -i string
        ID
  -level value
        level (default INFO)
  -o string
        oauth_token from accounts.google.com/embedded/setup/v2/android
  -s    single APK
  -v uint
        version code
baltpeter commented 2 months ago

And currently acquiring new apps seems to be broken:

❯ ./gplay -a -i com.YovoGames.babycare -b 2
msg=POST URL=https://android.googleapis.com/auth
msg=POST URL=https://android.clients.google.com/fdfe/acquire
panic: Fehler
Öffne "Meine Apps", um eine Verbindung mit dem Server herzustellen.

goroutine 1 [running]:
main.main()
    /home/benni/tmp/google/internal/play/main.go:62 +0x6b1
baltpeter commented 2 months ago

Maybe it's worth looking for another downloader, especially to use long term.

From some quick looking around, https://github.com/EFForg/apkeep currently seems like the only other viable version. Certainly seems a lot more stable and dependable.

baltpeter commented 2 months ago

Here's how I successfully set up apkeep:

  1. Install using cargo install apkeep.
  2. Fetch an oauth_token as explained above (the URL mentioned in https://github.com/EFForg/apkeep/blob/a2748ca6d04aff6da70e9926d1a6722cbff13ee8/USAGE-google-play.md didn't work for me).
  3. Run apkeep -e '<email>' --oauth-token '<oauth_token>'. This should print an AAS token.
  4. Create ~/.config/apkeep/apkeep.ini with the following contents:

    [google]
    email = <email>
    aas_token = <AAS token>

Now, you can download individual apps:

apkeep -a <app ID> -d google-play -o device=px_3a,locale=en_DE,include_additional_files=1,split_apk=1 <out dir>

Or even a whole list of apps:

apkeep -c <list.txt.> -d google-play -o device=px_3a,locale=en_DE,include_additional_files=1,split_apk=1 <out dir>

Refer to https://github.com/EFForg/apkeep/blob/a2748ca6d04aff6da70e9926d1a6722cbff13ee8/USAGE-google-play.md for the options.

Update: It is very important to include split_apk=1 (cf. https://github.com/tweaselORG/experiments/issues/2).