@@ -330,6 +330,45 @@ func (a *App) EnablePackage(packageName string) (string, error) {
330330 return "" , fmt .Errorf ("failed to enable package %s: %s" , packageName , output )
331331}
332332
333+ func (a * App ) PullApk (packageName string ) (string , error ) {
334+ if packageName == "" {
335+ return "" , fmt .Errorf ("package name cannot be empty" )
336+ }
337+
338+ pathOutput , err := a .runCommand ("adb" , "shell" , "pm" , "path" , packageName )
339+ if err != nil {
340+ return "" , fmt .Errorf ("failed to find package path for %s: %w" , packageName , err )
341+ }
342+
343+ if pathOutput == "" {
344+ return "" , fmt .Errorf ("package %s not found or no path returned" , packageName )
345+ }
346+
347+ remotePath := strings .TrimPrefix (pathOutput , "package:" )
348+ remotePath = strings .TrimSpace (remotePath )
349+
350+ if remotePath == "" {
351+ return "" , fmt .Errorf ("could not parse remote path from output: %s" , pathOutput )
352+ }
353+
354+ defaultFilename := packageName + ".apk"
355+
356+ localPath , err := a .SelectSaveFile (defaultFilename )
357+ if err != nil {
358+ return "" , fmt .Errorf ("save file dialog failed: %w" , err )
359+ }
360+
361+ if localPath == "" {
362+ return "APK pull cancelled by user" , nil
363+ }
364+
365+ output , err := a .runCommand ("adb" , "pull" , remotePath , localPath )
366+ if err != nil {
367+ return "" , fmt .Errorf ("adb pull failed: %w. Output: %s" , err , output )
368+ }
369+
370+ return fmt .Sprintf ("APK saved to %s" , localPath ), nil
371+ }
333372
334373func (a * App ) ListFiles (path string ) ([]FileEntry , error ) {
335374 output , err := a .runCommand ("adb" , "shell" , "ls" , "-lA" , path )
0 commit comments