更新记录

1.0.0(2026-05-25)

  • 初始版本
  • 支持扫描共享存储 .apk.1 文件(scanStorage
  • 支持从 content URI 导入文件(importFromUris
  • 支持读取 APK 元信息:包名、版本号、图标(Base64)
  • 支持安装 .apk.1 文件(自动剥离后缀,FileProvider 调起系统安装器)
  • 支持查询/刷新安装状态

平台兼容性

uni-app(4.87)

Vue2 Vue3 Chrome Safari app-vue app-vue插件版本 app-nvue app-nvue插件版本 Android Android插件版本 iOS 鸿蒙
- - - - 1.0.0 1.0.0 8.0 1.0.0 × ×
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
- - - - - - - - - - - -

uni-app x(4.87)

Chrome Safari Android iOS 鸿蒙 微信小程序
- - - - - -

hl-apk1-installer — .apk.1 安装器 UTS 插件

.apk.1 重命名包(及多层后缀 .apk.1.1.1 等)自动处理并调起 Android 系统安装器,无需用户手动重命名。同时支持接收其它 App 分享过来的 APK1 文件、转发文件到其它 App。

仅支持 Android(minSdk 26 / Android 8.0+)


功能

能力 函数
扫描存储中的 .apk.1 文件 scanStorage()
从 content URI 导入文件 importFromUris()
接收其它 App 分享过来的 Intent onSharedIntent()
安装文件(自动剥离后缀) installFile()
调起系统分享面板发送文件 shareFile()
查询安装未知应用权限 canInstall()
跳转安装权限设置页 openInstallSettings()
查询全盘存储访问权限 hasStorageAccess()
跳转全盘存储设置页 openStorageSettings()
批量删除文件 deleteFiles()
刷新文件的安装状态 refreshInstallStates()

快速上手

1. 扫描并安装

import * as Apk1Installer from '@/uni_modules/hl-apk1-installer'

// 扫描存储(需 MANAGE_EXTERNAL_STORAGE 权限,无权限时仅返回导入目录内容)
Apk1Installer.scanStorage((filesJson, error) => {
  if (error) { console.error('扫描失败:', error); return }
  const files = JSON.parse(filesJson)
  // files: ApkFileInfo[]
  console.log('找到', files.length, '个文件')
})

// 安装指定文件
Apk1Installer.installFile('/sdcard/Download/demo.apk.1', (success, msg) => {
  console.log(success ? '安装器已启动' : '失败: ' + msg)
})

2. 接收其它 App 分享过来的文件(推荐在页面 onLoad 中调用一次)

import * as Apk1Installer from '@/uni_modules/hl-apk1-installer'

export default {
  onLoad() {
    Apk1Installer.onSharedIntent((filesJson, error) => {
      if (error || !filesJson || filesJson === '[]') return
      const imported = JSON.parse(filesJson)
      // imported: ApkFileInfo[]—已复制到插件私有导入目录
      // 在这里提示用户是否立即安装
    })
  }
}

其他调用者可能发起的 Intent(插件内部已处理,无需区分):

  • ACTION_SEND:微信 / QQ / 邮箱等单文件分享
  • ACTION_SEND_MULTIPLE:多文件分享
  • ACTION_VIEW:文件管理器点击文件、浏览器下载打开

工作模式

  • 冷启动(App 未运行,其它 App 拉起本 App):onLoad 中调用 onSharedIntent 后,插件立即读取当前 Activity 的 Intent 并触发回调。
  • 热启动(App 在后台,收到新分享 Intent):插件通过 AppHookProxy + ActivityLifecycleCallbacks 监听 Activity onResume,自动读取新 Intent 并触发同一个已注册的回调。页面只需 onLoad 调用一次即可。

处理完成后插件会自动清空 Intent 的 action / data / EXTRA_STREAM,防止重复触发。

3. 转发文件到其它 App

import * as Apk1Installer from '@/uni_modules/hl-apk1-installer'

Apk1Installer.shareFile(file.filePath, (success, msg) => {
  console.log(success ? '分享面板已打开' : '失败: ' + msg)
})

已位于插件导入目录的文件直接通过 FileProvider 提供;共享存储中的文件先复制到 cacheDir/hl-apk1-share-cache/ 再提供,保留原始文件名。

4. 刷新安装状态

import * as Apk1Installer from '@/uni_modules/hl-apk1-installer'

// currentFilesJson 是上次 scanStorage/importFromUris 返回的 JSON 字符串
Apk1Installer.refreshInstallStates(currentFilesJson, (updatedJson) => {
  const files = JSON.parse(updatedJson)
  // 每个 file.installState 已更新
})

5. 权限检查与引导

import * as Apk1Installer from '@/uni_modules/hl-apk1-installer'

if (!Apk1Installer.canInstall()) {
  Apk1Installer.openInstallSettings() // 跳转「安装未知应用」权限页
}
if (!Apk1Installer.hasStorageAccess()) {
  Apk1Installer.openStorageSettings() // 跳转「全盘文件访问」权限页
}

6. 完整 demo 页面生命周期示例

import * as Apk1Installer from '@/uni_modules/hl-apk1-installer'

export default {
  data() { return { files: [] } },
  onLoad() {
    // 1) 请求权限
    if (!Apk1Installer.canInstall()) Apk1Installer.openInstallSettings()
    if (!Apk1Installer.hasStorageAccess()) Apk1Installer.openStorageSettings()

    // 2) 扫描已有文件
    Apk1Installer.scanStorage((json) => { this.files = JSON.parse(json) })

    // 3) 注册分享 Intent 回调(冷启动 + 热启动都会触发)
    Apk1Installer.onSharedIntent((json, error) => {
      if (error || !json || json === '[]') return
      const imported = JSON.parse(json)
      const ids = new Set(this.files.map(f => f.id))
      imported.forEach(f => { if (!ids.has(f.id)) this.files.unshift(f) })
      // 弹框询问是否立即安装...
    })
  }
}

ApkFileInfo 数据结构

{
  id:           string          // 文件绝对路径(唯一 ID)
  filePath:     string          // 磁盘绝对路径
  displayName:  string          // 文件名(含扩展名)
  appName:      string          // 应用名;解析失败时退化为文件名
  packageName:  string | null   // 包名;null = APK 解析失败
  versionName:  string | null   // 版本名称
  versionCode:  number          // 版本号;-1 = 无法获取
  sizeBytes:    number          // 文件字节大小
  modifiedAt:   number          // 最后修改时间(Unix 毫秒)
  installState: number          // 0=未安装  1=已安装  2=解析失败
  iconBase64:   string | null   // Base64 PNG 图标(无损)
  sourceKind:   number          // 0=存储扫描  1=手动导入
}

内部安装链路

installFile(filePath)
  ├─ 检查 canRequestPackageInstalls()
  │    └─ false → openInstallSettings() + callback(false)
  ├─ 复制到 cacheDir/hl-apk1-install-cache/<session>/<name>.apk
  ├─ Apk1FileProvider.getUriForFile(authority, tempApk)
  └─ startActivity(ACTION_VIEW, apk-mime, uri, FLAG_GRANT_READ_URI_PERMISSION)
        → 系统安装器弹窗

分享 Intent 接收机制

[冷启动]
  其它 App 发送 Intent → Android 拉起本 App
  → 页面 onLoad 调用 onSharedIntent(callback)
  → ApkBridge 读取 activity.intent + 存储 callback
  → importFromUris(uris, callback) → 复制到私有目录 → 回调为前端

[热启动]
  App 运行中 → 其它 App 发送新 Intent
  → Android 调用 Activity.onNewIntent(newIntent) → activity.intent 更新
  → Activity.onResume → AppHookProxy.onActivityResumed
  → ApkBridge.onActivityResumed() → 读取新 intent + 复用已存储 callback
  → 同上链路 → 回调为前端

依赖的 native 机制(插件内部已实现,无需外部配置):

  • index.uts 中导出 AppHookProxy implements UTSAndroidHookProxy
  • HBuilderX 自动在 Application.onCreate 时调用 AppHookProxy.onCreate
  • 在其中 application.registerActivityLifecycleCallbacks(...)
  • Lifecycle callback 中的 onActivityResumed 调用 ApkBridge.onActivityResumed()

文件目录约定

路径 用途
filesDir/hl-apk1-imports/ 通过 importFromUris / onSharedIntent 导入的文件(持久,随应用卸载清除)
cacheDir/hl-apk1-install-cache/ 安装临时 .apk 根目录;每次安装写入独立 session 子目录
cacheDir/hl-apk1-share-cache/ 分享临时文件(shareFile 复制共享存储文件时使用)

权限说明

权限 用途 必须
REQUEST_INSTALL_PACKAGES 调起系统安装器
MANAGE_EXTERNAL_STORAGE 全盘扫描(Android 11+) 否(无此权限仅扫描私有目录)
READ_EXTERNAL_STORAGE 旧版 Android 读文件
WRITE_EXTERNAL_STORAGE 旧版 Android 写文件

隐私、权限声明

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

REQUEST_INSTALL_PACKAGES / MANAGE_EXTERNAL_STORAGE / READ_EXTERNAL_STORAGE

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

无用户数据收集

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

暂无用户评论。