Skip to content

Commit

Permalink
Add ability to download .ipa by the app ID (#263)
Browse files Browse the repository at this point in the history
* Add ability to download .ipa by the app ID
* Update `download` command usage in README
* Fix the linter warnings
  • Loading branch information
altfoxie committed Apr 7, 2024
1 parent f68a119 commit 169af4b
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 15 deletions.
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,15 +107,17 @@ Usage:
ipatool download [flags]
Flags:
-b, --bundle-identifier string The bundle identifier of the target iOS app (required)
-i, --app-id int ID of the target iOS app (required)
-b, --bundle-identifier string The bundle identifier of the target iOS app (overrides the app ID)
-h, --help help for download
-o, --output string The destination path of the downloaded app package
--purchase Obtain a license for the app if needed
Global Flags:
--format format sets output format for command; can be 'text', 'json' (default text)
--non-interactive run in non-interactive session
--verbose enables verbose logs
--format format sets output format for command; can be 'text', 'json' (default text)
--keychain-passphrase string passphrase for unlocking keychain
--non-interactive run in non-interactive session
--verbose enables verbose logs
```

**Note:** the tool runs in interactive mode by default. Use the `--non-interactive` flag
Expand Down
24 changes: 17 additions & 7 deletions cmd/download.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,18 @@ func downloadCmd() *cobra.Command {
var (
acquireLicense bool
outputPath string
appID int64
bundleID string
)

cmd := &cobra.Command{
Use: "download",
Short: "Download (encrypted) iOS app packages from the App Store",
RunE: func(cmd *cobra.Command, args []string) error {
if appID == 0 && bundleID == "" {
return errors.New("either the app ID or the bundle identifier must be specified")
}

var lastErr error
var acc appstore.Account

Expand All @@ -43,13 +48,18 @@ func downloadCmd() *cobra.Command {
acc = loginResult.Account
}

lookupResult, err := dependencies.AppStore.Lookup(appstore.LookupInput{Account: acc, BundleID: bundleID})
if err != nil {
return err
app := appstore.App{ID: appID}
if bundleID != "" {
lookupResult, err := dependencies.AppStore.Lookup(appstore.LookupInput{Account: acc, BundleID: bundleID})
if err != nil {
return err
}

app = lookupResult.App
}

if errors.Is(lastErr, appstore.ErrLicenseRequired) {
err := dependencies.AppStore.Purchase(appstore.PurchaseInput{Account: acc, App: lookupResult.App})
err := dependencies.AppStore.Purchase(appstore.PurchaseInput{Account: acc, App: app})
if err != nil {
return err
}
Expand All @@ -74,7 +84,7 @@ func downloadCmd() *cobra.Command {
)
}

out, err := dependencies.AppStore.Download(appstore.DownloadInput{Account: acc, App: lookupResult.App, OutputPath: outputPath, Progress: progress})
out, err := dependencies.AppStore.Download(appstore.DownloadInput{Account: acc, App: app, OutputPath: outputPath, Progress: progress})
if err != nil {
return err
}
Expand Down Expand Up @@ -112,10 +122,10 @@ func downloadCmd() *cobra.Command {
},
}

cmd.Flags().StringVarP(&bundleID, "bundle-identifier", "b", "", "The bundle identifier of the target iOS app (required)")
cmd.Flags().Int64VarP(&appID, "app-id", "i", 0, "ID of the target iOS app (required)")
cmd.Flags().StringVarP(&bundleID, "bundle-identifier", "b", "", "The bundle identifier of the target iOS app (overrides the app ID)")
cmd.Flags().StringVarP(&outputPath, "output", "o", "", "The destination path of the downloaded app package")
cmd.Flags().BoolVar(&acquireLicense, "purchase", false, "Obtain a license for the app if needed")
_ = cmd.MarkFlagRequired("bundle-identifier")

return cmd
}
20 changes: 16 additions & 4 deletions pkg/appstore/appstore_download.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"io"
"os"
"strconv"
"strings"

"github.com/majd/ipatool/v2/pkg/http"
Expand Down Expand Up @@ -161,10 +162,21 @@ func (*appstore) downloadRequest(acc Account, app App, guid string) http.Request
}

func fileName(app App) string {
return fmt.Sprintf("%s_%d_%s.ipa",
app.BundleID,
app.ID,
app.Version)
var parts []string

if app.BundleID != "" {
parts = append(parts, app.BundleID)
}

if app.ID != 0 {
parts = append(parts, strconv.FormatInt(app.ID, 10))
}

if app.Version != "" {
parts = append(parts, app.Version)
}

return fmt.Sprintf("%s.ipa", strings.Join(parts, "_"))
}

func (t *appstore) resolveDestinationPath(app App, path string) (string, error) {
Expand Down

0 comments on commit 169af4b

Please sign in to comment.