如何从Android设备获取apk文件?

692

我该如何从Android设备获取apk文件?或者说,我该如何将apk文件从设备传输到系统?


3
你能把这个回答设为被采纳的回答吗? https://dev59.com/K2865IYBdhLWcg3wA5yc#18003462 它获得了超过10倍的投票数,并且让事情变得非常简单。 - Sam
26个回答

1963

对我来说,这些建议都没有用,因为Android会将序列号附加到包名上以生成最终的APK文件名。在较新版本的Android(Oreo和Pie)中,会附加一个不可预测的随机字符串。以下一系列命令是我在非ROOT设备上使用的解决方法:

1)确定应用程序的包名,例如“com.example.someapp”。如果您已经知道包名,则可以跳过此步骤。

adb shell pm list packages

浏览包名列表,尝试找到问题中的应用和包名之间的匹配。这通常很容易,但请注意,包名可能与应用名称完全无关。如果您无法从包名列表中识别应用程序,请尝试使用浏览器在Google Play中查找应用程序。 Google Play中应用程序的URL包含包名。

2)获取所需包的APK文件的完整路径名。

adb shell pm path com.example.someapp

输出结果将类似于
package:/data/app/com.example.someapp-2.apk
或者
package:/data/app/com.example.someapp-nfFSVxn_CTafgra3Fr_rXQ==/base.apk

3) 使用步骤2中的完整路径名,从Android设备拉取APK文件到开发电脑。

adb pull /data/app/com.example.someapp-2.apk path/to/desired/destination

87
这是最佳答案,无需对设备进行root操作!!非常感谢。 - Muhannad A.Alhariri
22
这在我所有的安卓设备上都有效,应该被接受为答案。 - b.mcewan
28
pm list packages 支持 -f 标志,可以为您列出 .apk 的位置,例如 package:/data/app/com.google.android.apps.maps-1.apk=com.google.android.apps.maps。内置的 pm 帮助无用,但 pm 也可以过滤包的类型,有关更多信息,请参见https://developer.android.com/studio/command-line/adb.html#pm。编辑:刚注意到下面的答案也提到了这一点,但该答案的赞数远不如这个。 - Hitechcomputergeek
17
对我没有用。我得到了以下错误信息:adb: error: remote object '/data/app/path.of.the.app-2/base.apk' does not exist。如果我使用文件浏览器浏览这些文件夹,它们是空的。 - Bevor
17
我遇到了类似于 @Bevor 的问题,拉取时出现了“apk不存在”的错误。通过使用 adb shell,然后运行 cp PathToApk /sdcard/ 将文件复制到sd卡中来解决了这个问题。 - colin
显示剩余20条评论

182

可以使用adb。通过 adb pull 命令,当设备连接到USB时,您可以将文件从设备复制到系统中。

当然,您还需要正确的权限来访问文件所在的目录。如果没有权限,则需要先对设备进行root。


如果您发现许多APK文件的名称为“base.apk”,您也可以使用这个一行命令将所有可访问的手机上的APK文件全部拉取下来,并将任何“base.apk”名称重命名为包名。 这也解决了似乎随机字符后跟APK路径的“找不到此目录”的问题:

for i in $(adb shell pm list packages | awk -F':' '{print $2}'); do 
  adb pull "$(adb shell pm path $i | awk -F':' '{print $2}')"
  mv base.apk $i.apk &> /dev/null 
done
如果你收到了“adb:error:failed to stat remote object”的错误提示,那就说明你没有所需的权限。我在一个非root的Moto Z2上运行了这个命令,并且成功下载了除YouTube以外的所有APK文件(见下文)。
adb shell pm uninstall --user 0 com.android.cellbroadcastreceiver   <--- kills presidential alert app!

(要查看用户,请运行adb shell pm list users) 这是一种在没有root权限的情况下删除/卸载(不会因为恢复出厂设置而重新安装)几乎所有应用程序的方法,包括系统应用程序(提示:可以通过grep“ ccc”来找到更新您手机的应用程序)。


1
谢谢Maurits Rijk。请帮我一下。我想将iTwips.apk文件从设备复制到系统中。我正在使用以下命令。它正确吗?我收到了错误消息“Android2.2Froyo/sdcard/iTwips.apk”不存在... /Users/bbb/Android/android-sdk-mac_86/tools/adb pull Android2.2Froyo/sdcard/iTwips.apk /Users/bbb。提前感谢您的帮助...... - Finder
28
实际上,您不需要root设备就可以提取apk文件。只要您知道该apk文件的完整路径。如果已安装了该apk文件,请通过首先查看包名称并使用“adb shell pm list packages”命令来找到其完整路径,“adb shell pm path your.package.name”,然后从计算机上,您可以简单地使用“adb pull /full/path/to/your.apk”命令。 - Isa A
2
请参考Yojimbo的答案,获取说明。 - methodsignature
1
值得注意的是,如果某些APK具有相同的名称,则会覆盖它们,因此您确实需要执行yojimbo指定的命令。 - Mama Foo
@Steven M RHetc:你的一行命令获取所有apk文件很好,但是对我来说它没有重命名任何“base.apk”文件。片段“2&>”的含义是什么?因为它似乎会破坏bash中的前面的mv命令,而我的谷歌搜索只返回了“2>&”示例。如果我将“2&>”更改为“2>”或“&>”(不带引号),它就可以工作了。此外,在我的情况下,“无法统计远程对象”的错误似乎都与拆分配置apk和它们的“adb shell pm path”多行结果有关。我可以手动提取所有拆分配置组件,所以没有权限问题。 - HendrikFrans
显示剩余8条评论

149

无需root权限:

这段代码将获取第三方软件包的路径及其名称,以便您可以轻松地识别您的APK。

adb shell pm list packages -f -3

输出结果将为

package:/data/app/XX.XX.XX.apk=YY.YY.YY

现在使用以下代码提取该包:

adb pull /data/app/XX.XX.XX.apk

如果您在 C:>\ 中执行了上述命令,则会发现该软件包已经存在于那里。


1
这是非常棒的答案!非常感谢 :) - Drag0
1
由于某些原因,我无法在我的 /data/app/ 目录中找到 APK 文件。那里总是有一个子目录。 - IgorGanapolsky
对于系统应用程序,请使用“-f -s”而不是“-f -3”。 - palindrom
如果您有很多APK文件,grep命令可以帮助缩小第一个命令的输出范围,只要您知道包名称中的任何单词:adb shell pm list packages -f | grep <包名称中的单词> - hBrent

66

从设备下载APK到桌面的步骤

A) 确保您正在运行(模拟器/真实设备)。使用此命令进行检查:

adb devices

adb devices

B) 选择所有已安装在您设备上的软件包列表。您可以使用grep命令选择要下载的特定软件包。

adb shell pm list packages
adb shell pm list packages -f -3

输出(可用软件包列表)

package:/data/app/com.example.mytestapplication-sOzKi5USzfbYLPNDmaaK6g==/base.apk=com.example.mytestapplication
package:/data/app/com.example.myapplication-nd1I4FGnTZnQ9PyRbPDHhw==/base.apk=com.example.myapplication

C) 从上面的链接中复制所需下载的软件包。对于我们的情况,我选择了这个(com.example.myapplication)软件包。

Syntax : adb shell pm path [your_package_name]
Command: adb shell pm path com.example.myapplication

输出

package:/data/app/com.example.myapplication-nd1I4FGnTZnQ9PyRbPDHhw==/base.apk

D) 最后,从您的(模拟器/真实设备)下载APK

Syntax : adb pull /data/app/[your_package_name]-1/base.apk  [your_destination_path]
Command: adb pull /data/app/com.example.myapplication-3j4CVk0Tb2gysElgjz5O6A==/base.apk /Users/$(whoami)/Documents/your_apk.apk

例子: 尝试将 CertInstaller.apk 文件拉到您的本地机器(Mac)中

adb pull /system/app/CertInstaller/CertInstaller.apk /Users/$(whoami)/Documents/APK/download_apk/

E) 在本地目录中确认

ls -la /Users/$(whoami)/Documents/

目标是提取单个apk,但在第4步中,您会拉出两个附加文件,而没有解释或先前的参考。 - Neithan Max
1
我通过澄清每个步骤修改了这篇文章。希望这种修改有助于易于理解。 - Farid Haq
另外,步骤C是什么?您已经从“pm list packages”中获取了软件包路径...只有在您只知道apk标识符(但不知道软件包路径)时才需要它。 - msanford

60

我看到很多解决这个问题的方法都要求你root你的手机或安装一个应用程序。然后经过大量搜索,我找到了这个适用于已root和未root手机的解决方案。

列出您目前拥有的应用程序。

adb shell pm list packages

那么您可以选择一个应用程序,例如 Twitter。

adb backup -apk com.twitter.android

一个重要的事情是不要设置密码来加密备份

这将会创建一个名为backup.ap的文件,但你仍然无法打开它。为此,你需要再次使用dd命令进行提取。

dd if=backup.ab bs=24 skip=1 | openssl zlib -d > backup.tar

完成这一步之后,您只需要提取tar内容即可完成。

希望对你们有帮助。


8
从http://blog.shvetsov.com/2013/02/access-android-app-data-without-root.html中获取,如果您的openssl没有zlib,可以尝试以下方法: dd if=backup.ab bs=1 skip=24 | python -c "import zlib,sys;sys.stdout.write(zlib.decompress(sys.stdin.read()))" | tar -xvf - - kodi
1
这是对我有效的方法,而不是被接受答案中的步骤。当我需要我的旧应用程序的 APK 但除了从我的手机获取之外无法获得时,它确实在今天帮助了我。 - zeeshan
1
如果您的 OpenSSL 缺少 zlib 支持,这里有更多信息:https://dev59.com/rV0a5IYBdhLWcg3w48Ln - Nico Wiedemann
1
如果你在使用@kodi的评论时遇到了UnicodeDecodeError: 'utf-8' codec can't decode byte 0xda in position 1: invalid continuation byte错误,那么请将命令中的python替换为python2 - Frank Kusters
在某些供应商的设备上,如果不设置密码,则无法备份APK。在三星手机上无效。 - Veniamin

24
C:\Users\xyz>adb shell pm list packages -f | findstr whatsapp
package:/data/app/com.whatsapp-1/base.apk=com.whatsapp

C:\Users\xyz>adb pull /data/app/com.whatsapp-1/base.apk Desktop
/data/app/com.whatsapp-1/base.apk: 1 f.... 13.8 MB/s (32803925 bytes in 
2.269s)

这是我认为最直接的方式。谢谢! - 8bitcartridge
4
使用Linux或Mac的人,不使用findstr而是使用grep。 - Jeeva

14

适用于所有Android版本的一行代码:

adb shell 'cat `pm path com.example.name | cut -d':' -f2`' > app.apk

1
@AlexP. 你想通过上面的链接告诉我们什么? - Vitaly Dyatlov

8
在Unix系统中,您可以尝试使用以下函数:
function android_pull_apk() {
    if [ -z "$1" ]; then
        echo "You must pass a package to this function!"
        echo "Ex.: android_pull_apk \"com.android.contacts\""
        return 1
    fi

    if [ -z "$(adb shell pm list packages | grep $1)" ]; then
        echo "You are typed a invalid package!"
        return 1
    fi

    apk_path="`adb shell pm path $1 | sed -e 's/package://g' | tr '\n' ' ' | tr -d '[:space:]'`"
    apk_name="`adb shell basename ${apk_path} | tr '\n' ' ' | tr -d '[:space:]'`"

    destination="$HOME/Documents/Android/APKs"
    mkdir -p "$destination"

    adb pull ${apk_path} ${destination}
    echo -e "\nAPK saved in \"$destination/$apk_name\""
}
  • 示例: android_pull_apk com.android.contacts
  • 注意: 要识别包名,请使用命令:adb shell pm list packages

7

补充@Yojimbo的答案,这是我所做的(仅适用于Linux/Mac,在Windows上不能直接使用...也许在git的bash shell中可以):

for i in $(adb shell pm list packages -f -3 | cut -d= -f 1 | cut -d ":" -f 2); do adb pull $i; done

这是丑陋的bash代码,但可以工作 :)

编辑: 在AndroidM上已经无法工作:所有文件都以另一个目录下的 "base.apk" 命名。应该很容易解决。


7

尝试使用这个一行命令备份你所有的应用程序:

for package in $(adb shell pm list packages -3 | tr -d '\r' | sed 's/package://g'); do apk=$(adb shell pm path $package | tr -d '\r' | sed 's/package://g'); echo "Pulling $apk"; adb pull -p $apk "$package".apk; done

这个命令基于Firelord的脚本。我只是将所有apk重命名为它们的包名,以解决elcuco的脚本中出现的问题,即在Android 6.0“Marshmallow”及以上版本上覆盖相同的base.apk文件。

请注意,此命令仅备份第三方应用程序,因为我不认为备份内置应用程序有意义。但是,如果您也想备份系统应用程序,请省略-3选项。

1
@Pieter 不太可能。这是在分割 APK 变得普遍之前测试的。这个脚本所做的是拉取 base.apk 并将其重命名为应用程序的包名。 - Rohan 'HEXcube' Villoth
@Pieter 你需要修改脚本,从该目录中提取所有apk并按顺序重命名它们,或者将它们复制到另一个目录中。 - Rohan 'HEXcube' Villoth
如果您只是分别进行adb install安装该应用的所有APK文件,那么它是否有效? - Pieter
根据这个 https://dev59.com/tFMI5IYBdhLWcg3w1fL- ,你需要使用一个新的命令 'adb install-multiple apk1 apk2 ...'。 - Rohan 'HEXcube' Villoth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接