通过ADB Shell或终端获取应用程序名称/标签

74

我正在开发一个使用ADB Shell与Android设备进行交互的应用程序,我需要一种打印应用程序名称或标签的方法,可能是通过包名获取。

简而言之,我需要一种通过adb shell获取用户安装的应用程序名称(例如“愤怒的小鸟v1.0.0”)的方法。

对此有何建议?感谢任何帮助。

7个回答

93

adb shell pm list packages将给你列出所有已安装包的名称列表。

然后可以使用dumpsys | grep -A18 "Package \[my.package\]"来获取包的信息,如版本标识符等。


12
为何在只需要 dumpsys package packages 的情况下要倾泻所有服务?此外,不需要使用 grep - dumpsys package 支持按包名称过滤。 - Alex P.
20
根据上述内容,我已经成功让以上代码能够转储软件包信息,但它并没有提供我所需的数据。 我指的是类似于 aapt d badging 的信息,其中我可以获取像 application-label: ES File ExplorerversionName='1.6.2.5' 这样的信息。 有没有什么东西可以通过 shell 给我这些信息? - hamsteyr
2
这个答案不起作用。dumpsys没有输出任何与“Package [package.name]”匹配或附近的文本,以帮助确定应用程序的标签。 dumpsys package列出了appLabel,但仅适用于少数应用程序(“BusyBox Pro”,“BusyBox”和“ ES File Manager”是我得到的5个左右)。有其他解决方案吗? - Michael Hoffmann
4
从您的 dumpsys | grep -A18 "Package \[my.package\]" 中无法找到 com.akh.livestream 包的完整应用程序名称。请注意,我会尽力使翻译更加通俗易懂,但不改变原文的意思。 - SebMa
1
这在 Android 11 上测试后不再起作用。 - Marvin
显示剩余4条评论

30

启动应用程序后,在命令提示符上输入以下命令:

adb shell dumpsys window windows | find "mCurrentFocus"

如果在Linux终端上执行命令,请将find替换为grep


变量 mCurrentFocusadb shell dumpsys window windows 的输出中不存在,因此查找或 grep 返回空。 - Ch Vas
如果上述解决方案无法使用find,请使用grep - Kamal Hossain
我发现这个很有用:adb shell dumpsys window windows | find "package" - Artem Mostyaev
如果在Windows环境中没有grep怎么办? - gumuruh
@gumuruh 在 Windows 平台上可以使用“find”命令,它相当于 Unix / Linux 平台上的“grep”命令。 - Akshay Kadam
显示剩余2条评论

12

如果你知道应用程序包的应用程序ID(例如org.mozilla.firefox),那么很容易。 首先获取应用程序ID的实际包文件的路径,

$  adb shell pm list packages -f com.google.android.apps.inbox
package:/data/app/com.google.android.apps.inbox-1/base.apk=com.google.android.apps.inbox

现在你可以使用grep | sed技巧提取路径:/data/app/com.google.android.apps.inbox-1/base.apk

之后aapt工具非常方便:

$  adb shell aapt dump badging /data/app/com.google.android.apps.inbox-1/base.apk
...
application-label:'Inbox'
application-label-hi:'Inbox'
application-label-ru:'Inbox'
...

再次使用 grep 魔法来获取标签。


9
最后一个命令无法运行,因为aapt只存在于您的开发者机器上。您需要先从设备中拉取apk文件。 - Six
1
即使在本地机器上使用它,"-f" 后面的参数就像通配符一样,所以如果有多个包含该字符串的包,它将显示多个包。最好的方法是:adb shell pm list packages -f 然后过滤结果。 - Smeterlink

4
一个用于实现这一目标的shell脚本:
#!/bin/bash

# Remove whitespace
function remWS {
    if [ -z "${1}" ]; then
        cat | tr -d '[:space:]'
    else
        echo "${1}" | tr -d '[:space:]'
    fi
}

for pkg in $(adb shell pm list packages -3 | cut -d':' -f2); do
    apk_loc="$(adb shell pm path $(remWS $pkg) | cut -d':' -f2 | remWS)"
    apk_name="$(adb shell aapt dump badging $apk_loc | pcregrep -o1 $'application-label:\'(.+)\'' | remWS)"
    apk_info="$(adb shell aapt dump badging $apk_loc | pcregrep -o1 '\b(package: .+)')"

    echo "$apk_name v$(echo $apk_info | pcregrep -io1 -e $'\\bversionName=\'(.+?)\'')"
done

1
这只是打印带有“v”的空行。 - lolung

3
为了找到应用程序的名称(应用程序标签),您需要执行以下操作:
(如其他答案所示)
  1. 找到您想要查找名称的应用程序的APK路径。
  2. 使用 aapt 命令,查找应用程序标签。
但是设备未预装 aapt 二进制文件。
因此,您需要先安装它。您可以从这里下载:
https://github.com/Calsign/APDE/tree/master/APDE/src/main/assets/aapt-binaries
请参阅此指南以获取完整步骤:
如何通过ADB Android使用包名查找应用程序名称?
(免责声明:我是该博客文章的作者)

1

非常感谢jcomeau_ictx提供了从apk中提取应用程序标签信息以及直接从手机中拉取apk的方法! 但是我不得不对脚本进行几次修改:

  1. while read line; do done由于while循环内部的命令与stdin/stdout交互而导致中断,因此while循环只运行一次然后停止。正如While loop stops reading after the first line in Bash - the comment from cmo所讨论的那样,我使用了提供的解决方案,并将while循环切换为使用未使用的文件描述符号9。
  2. 脚本实际上只需要一个包名称,adb shell pm list packages -f实在是太过冗长了,所以我将其更改为仅期望具有包列表的文件,并提供了一个从adb获取文件的示例。
  3. jcomeau_ictx脚本变体没有考虑到某些包可能有多个与之关联的apk,这会破坏脚本。
  4. 最后,我让每个变量都以下划线开头,这只是使脚本更易读的一种方式。

这里是同一脚本的另一个变体:

#!/bin/bash
_TOOLS=/opt/android-sdk-update-manager/build-tools/29.0.3
_AAPT=${_TOOLS}/aapt
#adb shell pm list packages --user 0 | sed -e 's|^package:||' | sort >./packages_list.txt
_PMLIST=packages_list.txt
rm ./packages_list_with_names.txt
_TEMP=$(echo $(adb shell mktemp -d -p /data/local/tmp) | sed 's/\r//')
mkdir -p packages
[ -f ${_PMLIST} ] || eval $(echo $(basename ${_PMLIST}) | tr '_' ' ') > ${_PMLIST}
while read -u 9 _line; do
    _package=${_line##*:}
    _apkpath=$(adb shell pm path ${_package} | sed -e 's|^package:||' | head -n 1)
    _apkfilename=$(basename "${_apkpath}")
    adb shell cp -f ${_apkpath} ${_TEMP}/copy.apk
    adb pull ${_TEMP}/copy.apk ./packages
    _name=$(${_AAPT} dump badging ./packages/copy.apk | sed -n 's|^application-label:\(.\)\(.*\)\1$|\2|p' )
#'
    echo "${_package} - ${_name}" >>./packages_list_with_names.txt
done 9< ${_PMLIST}
adb shell rm -rf $TEMP

sed --silent --regexp-extended "s/^application-label:'(.*)'$/\1/p" 这个怎么样?我认为这更容易理解(我的意思是单引号在明文中)。感谢您对脚本的改进。 - Andrei Korshikov
是的,这也可以工作,关于易读性,一切取决于你习惯使用什么,对我来说,在反斜杠屏蔽的情况下更容易阅读。 - hash

1

这是我刚想出来的。它会出现一些错误,但对我的需求来说足够好了,可以将包名称与标签匹配。

它会将所有软件包的副本拉入$PWD的子目录中,因此如果存储是一个问题,请记住这一点。

#!/bin/bash
TOOLS=~/Downloads/adt-bundle-linux-x86_64-20130717/sdk/build-tools/19.1.0
AAPT=$TOOLS/aapt
PMLIST=adb_shell_pm_list_packages_-f.txt
TEMP=$(echo $(adb shell mktemp -d -p /data/local/tmp) | sed 's/\r//')
mkdir -p packages
[ -f $PMLIST ] || eval $(echo $(basename $PMLIST) | tr '_' ' ') > $PMLIST
while read line; do
 package=${line##*:}
 apk=${package%%=*}
 name=${package#*=}
 copy=packages$apk
 mkdir -p $(dirname $copy)
 if [ ! -s $copy ]; then  # copy it because `adb pull` doesn't see /mnt/expand/
  adb shell cp -f $apk $TEMP/copy.apk
  adb pull $TEMP/copy.apk $copy
 fi
 label=$($AAPT dump badging $copy || echo ERROR in $copy >&2 | \
  sed -n 's/^application-label:\(.\)\(.*\)\1$/\2/p')
 echo $name:$label
done < <(sed 's/\r//' $PMLIST)
adb shell rm -rf $TEMP

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