更新记录

1.0.0(2026-08-27) 下载此版本

首发版本。

功能

  • 获取安卓设备已安装应用列表,支持 all(全部)/ system(系统应用)/ user(用户应用)三种筛选
  • 获取单个应用信息(按包名查询)
  • 返回字段:应用名称、包名、版本名称、版本号、是否系统应用、是否启用、应用图标本地路径(file:///
  • 应用图标自动提取并缓存(缩放至 96px + 按包名命名,二次查询复用)
  • 全部耗时操作在后台 IO 线程执行,主线程不卡顿、杜绝 ANR 闪退

说明

  • 支持平台:Android(仅 App 端)
  • 无三方依赖,仅使用 Android 系统 API
  • 需自定义基座运行(插件声明 QUERY_ALL_PACKAGES 权限,Android 11+ 查询全部应用必需)

平台兼容性

uni-app x(4.66)

Chrome Safari Android iOS 鸿蒙 微信小程序
× × 5.0 × × ×

其他

多语言 暗黑模式 宽屏模式

losfer-appinfo 安卓应用信息列表插件

适用于 uni-app x(HBuilderX 4.66+,Android 平台),获取安卓设备已安装应用列表与应用详细信息。

获取手机中全部应用 / 系统应用 / 用户应用的列表,以及单个应用的信息,包括:应用图标、名称、包名、版本名称、版本号、是否系统应用、是否启用

  • 插件类型:UTS 插件(API)
  • 支持平台:Android(仅 App 端)
  • 无任何三方依赖,原生代码仅使用 Android 系统 API
  • 所有耗时操作(遍历应用、读取版本号、压缩图标)均在后台线程执行,不会卡死主线程,杜绝闪退

一、功能特性

功能 说明
🔍 获取已安装应用列表 支持筛选:all 全部 / system 系统应用 / user 用户应用
📦 单个应用信息 根据包名查询单个应用详情
🖼️ 应用图标 自动提取应用图标并缓存到本地(file:/// 路径,可直接用于 <image>
📄 详细信息 应用名称、包名、版本名称、版本号(versionCode)、是否系统应用、是否启用
⚡ 异步执行 全部耗时操作在后台 IO 线程执行,主线程不卡顿
🚀 高性能 图标统一缩放至 96px + 按包名缓存,二次查询直接复用,零重复压缩

二、安装引入

uni_modules/losfer-appinfo 目录复制到项目 uni_modules/ 下即可。

.uvue 页面中引入:

// #ifdef APP-ANDROID
import { getInstalledApps, getAppInfo, AppInfo,
         GetInstalledAppsOptions, GetInstalledAppsResult,
         GetInstalledAppsFail, GetAppInfoOptions } from '@/uni_modules/losfer-appinfo'
// #endif

建议使用条件编译 #ifdef APP-ANDROID,插件仅支持安卓端 App。


三、API 说明

1. 获取已安装应用列表 getInstalledApps(options)

getInstalledApps(options : GetInstalledAppsOptions) : void

参数 options:

名称 类型 必填 说明
type string 应用类型筛选:'all' 全部 / 'system' 系统应用 / 'user' 用户应用
success (res: GetInstalledAppsResult) => void 成功回调
fail (err: GetInstalledAppsFail) => void 失败回调

success 返回值 res:

{
    list: Array<AppInfo>
}

2. 获取单个应用信息 getAppInfo(options)

getAppInfo(options : GetAppInfoOptions) : void

参数 options:

名称 类型 必填 说明
packageName string 应用包名
success (res: AppInfo) => void 成功回调
fail (err: GetInstalledAppsFail) => void 失败回调

3. 数据结构

AppInfo(单个应用信息):

字段 类型 说明
packageName string 应用包名(唯一标识)
appName string 应用名称
versionName string 版本名称,如 1.0.0
versionCode number 版本号(versionCode)
isSystemApp boolean 是否系统应用
enabled boolean 是否处于启用状态
iconPath string 应用图标本地路径(file:/// 格式),可直接用于 <image :src>

GetInstalledAppsFail(失败信息):

字段 类型 说明
errCode number 错误码
errMsg string 错误描述

错误码:

errCode 说明
1002 type 参数不合法,仅支持 all / system / user
1003 packageName 不能为空
1004 未找到指定包名的应用

四、使用示例

示例 1:获取全部应用列表并展示

<template>
    <view class="page">
        <button @click="loadApps">获取全部应用</button>
        <view class="app-item" v-for="item in appList" :key="item.packageName">
            <image class="app-icon" :src="item.iconPath"></image>
            <view class="app-info">
                <text class="app-name">{{ item.appName }}</text>
                <text class="app-pkg">{{ item.packageName }} v{{ item.versionName }}</text>
            </view>
            <text class="app-tag">{{ item.isSystemApp ? '系统' : '用户' }}</text>
        </view>
    </view>
</template>

<script setup lang="uts">
    import { ref } from 'vue'
    // #ifdef APP-ANDROID
    import { getInstalledApps, AppInfo,
             GetInstalledAppsOptions, GetInstalledAppsResult,
             GetInstalledAppsFail } from '@/uni_modules/losfer-appinfo'
    // #endif

    const appList = ref<Array<AppInfo>>([])

    function loadApps() {
        // #ifdef APP-ANDROID
        const opts : GetInstalledAppsOptions = {
            type: 'all',
            success: (res : GetInstalledAppsResult) => {
                appList.value = res.list
                console.log('获取到 ' + res.list.length + ' 个应用')
            },
            fail: (err : GetInstalledAppsFail) => {
                console.log('获取失败: ' + err.errMsg)
            }
        }
        getInstalledApps(opts)
        // #endif
    }
</script>

<style>
    .page { flex-direction: column; padding: 20rpx; }
    .app-item { flex-direction: row; align-items: center; padding: 16rpx 0; }
    .app-icon { width: 72rpx; height: 72rpx; border-radius: 12rpx; margin-right: 20rpx; }
    .app-info { flex: 1; flex-direction: column; }
    .app-name { font-size: 15px; font-weight: bold; }
    .app-pkg { font-size: 12px; color: #888; margin-top: 4rpx; }
    .app-tag { font-size: 12px; color: #409eff; }
</style>

示例 2:筛选系统应用 / 用户应用

// 仅系统应用
getInstalledApps({
    type: 'system',
    success: (res : GetInstalledAppsResult) => { /* ... */ }
})

// 仅用户应用
getInstalledApps({
    type: 'user',
    success: (res : GetInstalledAppsResult) => { /* ... */ }
})

示例 3:查询单个应用信息

// #ifdef APP-ANDROID
const opts : GetAppInfoOptions = {
    packageName: 'cn.losfer.aitools',
    success: (info : AppInfo) => {
        console.log(info.appName, info.versionName, info.iconPath)
    },
    fail: (err : GetInstalledAppsFail) => {
        uni.showToast({ title: err.errMsg, icon: 'none' })
    }
}
getAppInfo(opts)
// #endif

五、典型案例页面代码

以下为「应用管理」页完整代码,演示:类型切换、列表获取、图标展示、单包名精确查询。

<template>
    <view class="page">
        <!-- 类型切换 -->
        <view class="filter-bar">
            <text :class="type == 'all' ? 'filter-item active' : 'filter-item'" @click="setType('all')">全部</text>
            <text :class="type == 'system' ? 'filter-item active' : 'filter-item'" @click="setType('system')">系统</text>
            <text :class="type == 'user' ? 'filter-item active' : 'filter-item'" @click="setType('user')">用户</text>
        </view>

        <!-- 应用列表 -->
        <scroll-view class="list" :scroll-y="true">
            <view class="app-item" v-for="(item, index) in appList" :key="item.packageName">
                <image class="app-icon" :src="item.iconPath"></image>
                <view class="app-info">
                    <text class="app-name">{{ item.appName }}</text>
                    <text class="app-pkg">{{ item.packageName }}</text>
                    <text class="app-ver">版本:{{ item.versionName }}({{ item.versionCode }})</text>
                </view>
                <view class="app-right">
                    <text :class="item.isSystemApp ? 'tag tag-system' : 'tag tag-user'">
                        {{ item.isSystemApp ? '系统' : '用户' }}
                    </text>
                    <text :class="item.enabled ? 'tag tag-on' : 'tag tag-off'">
                        {{ item.enabled ? '已启用' : '已禁用' }}
                    </text>
                </view>
            </view>
            <view class="empty" v-if="appList.length == 0">
                <text class="empty-text">暂无数据,点击获取</text>
            </view>
        </scroll-view>

        <!-- 底部操作栏 -->
        <view class="bottom-bar">
            <button type="primary" @click="loadApps">获取列表</button>
            <button @click="clearList">清空</button>
        </view>
    </view>
</template>

<script setup lang="uts">
    import { ref } from 'vue'
    // #ifdef APP-ANDROID
    import { getInstalledApps, AppInfo,
             GetInstalledAppsOptions, GetInstalledAppsResult,
             GetInstalledAppsFail } from '@/uni_modules/losfer-appinfo'
    // #endif

    const type = ref<string>('all')
    const appList = ref<Array<AppInfo>>([])

    function setType(t : string) {
        type.value = t
        loadApps()
    }

    function loadApps() {
        // #ifdef APP-ANDROID
        const opts : GetInstalledAppsOptions = {
            type: type.value,
            success: (res : GetInstalledAppsResult) => {
                appList.value = res.list
                uni.showToast({ title: '共 ' + res.list.length + ' 个应用', icon: 'none' })
            },
            fail: (err : GetInstalledAppsFail) => {
                uni.showToast({ title: err.errMsg, icon: 'none' })
            }
        }
        getInstalledApps(opts)
        // #endif
    }

    function clearList() {
        appList.value = []
    }
</script>

<style>
    .page { flex: 1; flex-direction: column; background-color: #f7f8fa; }
    .filter-bar { flex-direction: row; padding: 20rpx; }
    .filter-item { margin-right: 30rpx; font-size: 14px; color: #666; }
    .filter-item.active { color: #409eff; font-weight: bold; }
    .list { flex: 1; padding: 0 20rpx; }
    .app-item {
        flex-direction: row;
        align-items: center;
        background-color: #fff;
        border-radius: 16rpx;
        padding: 20rpx;
        margin-bottom: 16rpx;
    }
    .app-icon { width: 80rpx; height: 80rpx; border-radius: 14rpx; margin-right: 20rpx; }
    .app-info { flex: 1; flex-direction: column; }
    .app-name { font-size: 15px; font-weight: bold; color: #222; }
    .app-pkg { font-size: 12px; color: #888; margin-top: 4rpx; }
    .app-ver { font-size: 12px; color: #aaa; margin-top: 4rpx; }
    .app-right { flex-direction: column; align-items: flex-end; }
    .tag { font-size: 11px; padding: 4rpx 12rpx; border-radius: 8rpx; margin-top: 6rpx; }
    .tag-system { color: #e6a23c; background-color: #fdf6ec; }
    .tag-user { color: #409eff; background-color: #ecf5ff; }
    .tag-on { color: #67c23a; background-color: #f0f9eb; }
    .tag-off { color: #909399; background-color: #f4f4f5; }
    .empty { align-items: center; padding: 80rpx 0; }
    .empty-text { color: #bbb; }
    .bottom-bar { flex-direction: row; justify-content: space-between; padding: 20rpx; }
</style>

六、运行要求

  • HBuilderX 4.66+,uni-app x 项目,Android 平台
  • 下列插件模块依赖原生配置或使用了 QUERY_ALL_PACKAGES 权限,需要自定义基座才能生效:
    • AndroidManifest.xml 声明了 android.permission.QUERY_ALL_PACKAGES(Android 11+ 查询所有已安装应用必需)
    • 首次在真机调试:HBuilderX 菜单「运行 → 运行到手机或模拟器 → 制作自定义调试基座」,安装自定义基座后运行
  • 不依赖任何三方 SDK,云端打包无需额外配置

⚠️ Android 11(API 30)及以上:查询所有已安装应用需要 QUERY_ALL_PACKAGES 权限。Google Play 对该权限有合规审核要求,若仅用于系统工具类 App 通常可过审;企业内部应用(AAB 私发)不受影响。


七、FAQ

Q1:为什么点击获取后列表为空?

  • 确认已使用自定义基座运行(插件声明了原生权限)
  • Android 11+ 确认已安装 QUERY_ALL_PACKAGES 权限
  • 查看 HBuilderX 控制台筛选插件日志 [losfer-appinfo]

Q2:图标不显示?

  • iconPathfile:/// 本地路径,<image> 组件支持该格式
  • 首次生成图标需要几秒(后台线程),列表会先返回、图标路径待文件写入后即可使用
  • 缓存目录在应用外部/内部缓存目录(app_icons/),清缓存后会自动重新生成

Q3:会不会卡死 App?

  • 不会。所有耗时操作在后台 IO 线程执行,主线程只负责收结果刷新界面

Q4:为什么有的应用版本号为 0?

  • 部分系统内置应用(如系统设置)无法读取版本信息,属正常现象

八、更新日志

版本 说明
1.0.0 首发:获取应用列表(all/system/user)、单个应用信息、图标缓存、后台线程异步执行

隐私、权限声明

1. 本插件需要申请的系统权限列表:

android.permission.QUERY_ALL_PACKAGES(查询所有已安装应用,Android 11+ 需要)

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

插件不采集任何数据

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

许可协议

MIT协议

暂无用户评论。