# 技术信息

## 权限、设备使用列表


```json
[
  {
    "权限": "android.permission.WAKE_LOCK",
    "场景": "阻止系统休眠",
    "说明": "保持微信native层网络组件需要。防止网络请求进行中被休眠/屏幕息屏打断。发起网络请求时获取WAKE_LOCK, 请求结束后释放。必须"
  },
  {
    "权限": "android.permission.ALARM_LOCK",
    "场景": "ALARM_LOCK",
    "说明": "ALARM_LOCK"
  },
  {
    "权限": "android.permission.ACCESS_COARSE_LOCATION",
    "场景": "通过网络得到粗略位置",
    "说明": "允许小程序访问位置时使用：[小程序定位接口](/miniprogram/dev/api/location/wx.getFuzzyLocation.md)、[地图组件](/miniprogram/dev/component/map.md)等\n对于后台定位权限，小程序需要在其`app.json`内[声明其需要后台定位权限](/miniprogram/dev/reference/configuration/app.md#requiredBackgroundModes)"
  },
  {
    "权限": "android.permission.ACCESS_FINE_LOCATION",
    "场景": "通过 GPS 得到精确位置",
    "说明": ""
  },
  {
    "权限": "android.permission.ACCESS_BACKGROUND_LOCATION",
    "场景": "后台获取位置信息",
    "说明": ""
  },
  {
    "权限": "android.permission.READ_EXTERNAL_STORAGE",
    "场景": "读取小程序存储",
    "说明": "框架需要读写日志、[小程序存储](/miniprogram/dev/api/storage/wx.getStorageSync.md) 等信息至 [getExternalFilesDir](https://developer.android.com/reference/android/content/Context#getExternalFilesDir(java.lang.String)) 位置，如 `/storage/emulated/0/Android/data/com.tencent.wmpf`。"
  },
  {
    "权限": "android.permission.WRITE_EXTERNAL_STORAGE",
    "场景": "保存日志、写入小程序存储",
    "说明": ""
  },
  {
    "权限": "android.permission.ACCESS_NETWORK_STATE",
    "场景": "检测网络的可用性. 需要网络运营商相关信息用于网络定位",
    "说明": "允许程序访问当前网络状态"
  },
  {
    "权限": "android.permission.CHANGE_NETWORK_STATE",
    "场景": "访问网络的变化, 需要某些信息用于网络定位.网络状态恢复时重启下载任务",
    "说明": "改变网络状态如是否能联网"
  },
  {
    "权限": "android.permission.ACCESS_WIFI_STATE",
    "场景": "访问WiFi状态.",
    "说明": "获取当前WiFi接入的状态以及WLAN热点的信息，允许小程序访问[WiFi 接口](/miniprogram/dev/framework/device/wifi.md)"
  },
  {
    "权限": "android.permission.CHANGE_WIFI_STATE",
    "场景": "发起WiFi扫描, 需要WiFi信息用于网络定位",
    "说明": ""
  },
  {
    "权限": "android.permission.CHANGE_WIFI_MULTICAST_STATE",
    "场景": "获取局域网内其他设备或服务",
    "说明": "[投屏](/miniprogram/dev/api/media/video/VideoContext.startCasting.md)"
  },
  {
    "权限": "android.permission.INTERNET",
    "场景": "访问网络, 必须",
    "说明": "小程序需要网络才能运行"
  },
  {
    "权限": "android.permission.RECORD_AUDIO",
    "场景": "语音输入场景, VOIP通话场景s",
    "说明": "允许小程序调用[录制音频](/miniprogram/dev/api/media/recorder/RecorderManager.md)、[实时音视频](/miniprogram/dev/component/live-pusher.md)、[多人音视频对话](/miniprogram/dev/component/voip-room.md)等"
  },
  {
    "权限": "android.permission.BLUETOOTH",
    "场景": "小程序与蓝牙设备配对并通信",
    "说明": "允许小程序访问[蓝牙/BLE接口](/miniprogram/dev/framework/device/bluetooth.md)等"
  },
  {
    "权限": "android.permission.BLUETOOTH_ADMIN",
    "场景": "小程序与蓝牙设备配对并通信",
    "说明": ""
  },
  {
    "权限": "android.permission.CAMERA",
    "场景": "相机",
    "说明": "允许小程序调用[扫一扫](/miniprogram/dev/api/device/scan/wx.scanCode.md)、[摄像头组件](/miniprogram/dev/component/camera.md)、[实时音视频录制组件](/miniprogram/dev/component/live-pusher.md)、[多人音视频对话组件](/miniprogram/dev/component/voip-room.md)等\r\n\n如小程序可以通过摄像头扫描二维码、识别文本、拍照、识别物体等。\r\n\nWMPF 内可以通过 Camera、Camera2 接口访问摄像头。\r\n\n车机场景默认屏蔽摄像头权限。"
  },
  {
    "权限": "android.permission.VIBRATE",
    "场景": "使 Android 设备短暂或较长时间震动",
    "说明": "允许小程序调用[短时震动](/miniprogram/dev/api/device/vibrate/wx.vibrateShort.md)、[长时震动](/miniprogram/dev/api/device/vibrate/wx.vibrateLong.md)"
  },
  {
    "权限": "android.permission.NFC",
    "场景": "近场通信 NFC",
    "说明": "允许小程序调用 [NFC 接口](/miniprogram/dev/framework/device/nfc.md)"
  },
  {
    "权限": "android.permission.MODIFY_AUDIO_SETTINGS",
    "场景": "修改全局音频设置",
    "说明": "修改全局音频设置、[多人音视频对话组件](/miniprogram/dev/component/voip-room.md)"
  },
  {
    "权限": "android.permission.SYSTEM_ALERT_WINDOW",
    "场景": "悬浮窗权限",
    "说明": "框架需要系统悬浮窗权限才能通过悬浮窗模式打开小程序"
  },
  {
    "权限": "android.permission.FOREGROUND_SERVICE",
    "场景": "通过前台服务进行调用导航、录音、摄像头等功能, 必须",
    "说明": "由于悬浮窗小程序不被系统认为是前台应用，需要前台服务权限允许悬浮窗小程序调用前台定位、录音、摄像头等权限"
  },
  {
    "权限": "android.car.permission.CAR_CONTROL_AUDIO_VOLUME",
    "场景": "设置音量",
    "说明": "允许用户划动小程序视频播放组件时调节音量。无此权限时将回退到 AudioManager 相关接口控制音量。"
  }
]
```


## 必须预先授予的权限

以下是系统须预先授权 WMPF 应用的权限：
| 权限 | 说明 |
| --- | --- |
| android.permission.INTERNET | 框架需要网络才能运行 |
| android.permission.SYSTEM_ALERT_WINDOW | 悬浮窗权限，部分 Android 系统若未附带设置应用，必须预先授权 WMPF 悬浮窗权限才能打开悬浮窗小程序 |
| android.permission.FOREGROUND_SERVICE | 悬浮窗权限，部分 Android 系统若未附带设置应用，必须预先授权 WMPF 悬浮窗权限才能打开悬浮窗小程序 |
| 后台弹出页面权限 | 通过 wmpf-cli 接口启动小程序时需要该权限 |
| 自启动权限 | 调用 wmpf-cli 接口时需要该权限 |

## Android Car API 使用列表

| 接口 | 用途 |
| -- | -- |
| `android.car.media.CarAudioManager.getVolumeGroupIdForUsage` | 根据 StreamType 获取 GroupId |
| `android.car.media.CarAudioManager.getGroupVolume` | 根据 GroupId 获取当前音量，小程序 `<video>` 组件设置音量能力依赖该接口 |
| `android.car.media.CarAudioManager.getGroupMaxVolume` | 根据 GroupId 获取最大音量，小程序 `<video>` 组件设置音量能力依赖该接口 |
| `android.car.media.CarAudioManager.setGroupVolume` | 根据 GroupId 设置音量，小程序 `<video>` 组件设置音量能力依赖该接口 |
| `android.car.media.CarAudioManager.setGroupVolume` | 根据 GroupId 设置音量，小程序 `<video>` 组件设置音量能力依赖该接口 |

## 定位方式

目前 WMPF 会调用以下接口获取系统定位信息


```json
[
  {
    "服务": "LocationManager \n GPS 定位",
    "方法": "requestLocationUpdates"
  },
  {
    "服务": "registerGnssStatusCallback",
    "方法": ""
  },
  {
    "服务": "getLastKnownLocation",
    "方法": ""
  },
  {
    "服务": "isProivderEnabled",
    "方法": ""
  },
  {
    "服务": "TelephonyManager \n 基站定位",
    "方法": "getAllCellInfo"
  },
  {
    "服务": "getCellLocation",
    "方法": ""
  },
  {
    "服务": "requestCellInfoUpdate",
    "方法": ""
  },
  {
    "服务": "getSimState",
    "方法": ""
  },
  {
    "服务": "listen",
    "方法": ""
  },
  {
    "服务": "WifiManager \n 室内定位",
    "方法": "isWifiEnabled"
  },
  {
    "服务": "isScanAlwaysAvailable",
    "方法": ""
  },
  {
    "服务": "getScanResults",
    "方法": ""
  },
  {
    "服务": "startScan",
    "方法": ""
  },
  {
    "服务": "getWifiState",
    "方法": ""
  }
]
```


## 匿名 Intent 使用列表

| 匿名 Intent ACTION | 用途 |
| - | - |
| Intent.ACTION_GET_CONTENT | 小程序选择文件 |
| Intent.ACTION_INSERT | 小程序添加联系人、添加日历 |
| Intent.ACTION_INSERT_OR_EDIT | 小程序添加联系人 |
| Intent.ACTION_PICK | 扫一扫选择相册图片、小程序选择联系人 |
| Intent.ACTION_VIEW | 小程序打开 PDF 文件 |
| Intent.ACTION_DIAL | 小程序拨打电话（如拨打商家电话） |
| Intent.ACTION_CHOOSER | 小程序选择文件 |
| MediaStore.ACTION_IMAGE_CAPTURE | 小程序调用系统应用拍照 |
| MediaStore.ACTION_VIDEO_CAPTURE | 小程序调用系统应用录像 |
| Settings.ACTION_MANAGE_OVERLAY_PERMISSION | 申请悬浮窗权限 |
| Settings.ACTION_WIFI_SETTINGS | 小程序跳转要求用户连接指定 WiFi |
| Settings.ACTION_NFC_SETTINGS | 小程序框架没有 NFC 权限时，跳转授权 |
| Settings.ACTION_LOCATION_SOURCE_SETTINGS | 定位时未打开 GPS 开关可能提示用户打开 GPS 开关 |
| Settings.ACTION_MANAGE_APPLICATIONS_SETTINGS | 小程序框架没有摄像头权限时跳转授权 |

## 其他技术信息

### 域名名单

**注意：由于框架层无法控制小程序访问的域名列表，接入方需要自行测算小程序访问的域名列表并予以设置白名单**

对于部分使用物联网卡的设备，需要设置域名白名单，以下是 WMPF 框架层使用的域名白名单：
| 域名 | 说明 |
| -- | -- |
| servicewechat.com | 查询小程序信息、下载代码包等 |
| launchwxacode.wxqcloud.qq.com.cn | 下载代码包 |

### 音频播放

利用系统解码器，解码后通过 AudioTrack 接口播放。音频播放的采样率、音频格式均由小程序开发者决定。StreamType 默认为 `AudioManager.STREAM_MUSIC`。

音频焦点抢占逻辑：
* 对于背景音频，其他应用抢占音频焦点后，背景音频将暂停播放。WMPF 重新获得焦点后，将继续播放背景音频。
* 对于游戏音频和应用内调用 `wx.createInnerAudioContext` 接口播放的音频，小程序开发者可以选择在丢失音频焦点后混播或者暂停音频播放。框架不限制混播（如车机蓝牙电话和游戏音频混播）。

### 是否自带输入法？

小程序 `<input>` 组件需要输入身份号码、纯数字键盘时，会使用 WMPF 内置的数字键盘。

### OpenGL ES
WMPF 需要 OpenGL ES 以支持小程序 webview、小游戏、小程序 canvas 渲染。

### 存储空间

WMPF 存储空间主要由以下几部分组成，提供给 WMPF 的存储空间要在 2G 以上：
* 小程序代码包、编译缓存
* 小程序自身数据缓存、图片缓存
* 小程序自身数据存储
* XWeb 浏览器内核

其中存储空间会和用户使用过的小程序数目、时长有关，没有上限。

你可以通过 `WMPF.getInstance().trimStorage` 接口来按需清理 WMPF 存储空间。需要注意如果清理小程序代码包，会因为重新下载必要的小程序代码包而增大下载小程序代码包产生的流量消耗。

### 流量消耗

WMPF 网络请求主要由以下几部分组成：
* 小程序桌面列表、小程序图标、微信登录
* 小程序代码包下载
* 小程序内图片
* 小程序自身网络请求

WMPF 可能在如下场景下，即使设备连接了 WiFi 也会使用数据流量：
* 实时音视频通话：通过数据流量改善通话体验
* 基于基站的定位

### 后台行为

WMPF 会因为但不限于以下几个场景在后台运行：
| 场景 | 说明 |
| -- | -- |
| 关闭小程序 | 用户点击小程序右上角胶囊按钮将使小程序切换至后台，小程序一般有 30 秒的后台存活时间，超时后若小程序没有请求后台执行权限，小程序将被暂停。 |
| 后台定位 | 小程序若声明后台定位权限，小程序将可以在后台运行 |
| 后台背景音频播放 | 小程序若声明后台音频播放权限，小程序将可以在后台播放音频 |
| 后台音视频通话 | 小程序若正在音视频通话期间，小程序可以在后台录制音频和视频并维持通话 |
| 小程序智能助手 | 若调用 WMPFMiniProgramAgentApi 接口触发小程序智能助手，小程序将在后台运行 |
| 调用 wmpf-cli 接口 | 若系统调用了 WMPF 接口，WMPF 将被唤醒并响应接口调用 |

### 多用户支持

由于 WMPF 并非必须以系统应用的方式安装，WMPF 未专门支持 Android 系统的多用户能力。系统侧可以通过 Android 系统默认的多用户多进程并隔离存储空间的方式实现多用户支持。

### IPC 机制

wmpf-cli 接口通过 ContentProvider、Binder（AIDL）等方式允许接入 App 和 WMPF 进程通信。

#### ContentProvider 通信列表
| ContentProvider authority | 说明 |
| - | - |
| com.tencent.wmpf.cli.provider | WMPF 连接 wmpf-cli 的 ContentProvider，wmpf-cli 部分接口 (设备登录通知、InvokeChannel) 通过 ContentProvider 提供 |
| com.tencent.wmpf.comm.provider | wmpf-cli 连接 WMPF 的 ContentProvider，wmpf-cli 部分接口 (设备登录通知、InvokeChannel) 通过 ContentProvider 提供 |
| com.tencent.luggage.jsapi.voiceassist.VoiceAssistContentProvider | 目前未在使用 |

#### Binder 通信列表
| Service | 说明 |
| - | - |
| com.tencent.wmpf.app.WMPFService | wmpf-cli 连接 WMPF 的 Service |
| com.tencent.wmpf.app.WMPFBoot$WMPFCliMainProcessService | WMPF 连接 wmpf-cli 的 Service |
| com.tencent.wmpf.car_sdk.contract.WMPFMusicService | 背景音频 MediaBrowserService |

#### Activity 列表
| Activity | 说明 |
| - | - |
| com.tencent.wmpf.launcher.LauncherDesktopActivity | 车机版小程序中心 Launcher |
| com.tencent.wmpf.opensdk.WXEntryActivity | 和车载微信交互的 Activity |
| com.tencent.wmpf.shortcut.WXShortcutEntryActivity | 桌面快捷方式图标入口 Activity |
| com.tencent.wmpf.wakeup.WMPFWakeUpInvokeActivity | wmpf-cli 接入 App 可以通过该 Activity 唤醒 WMPF |

对于系统内存在车载微信的情况，WMPF 将会与车载微信通过微信 opensdk（内部通过 Activity intent）进行通信，intent 安全性由车载微信保证。

## 开源软件使用列表

| 包名:版本 | 开源协议 | 用途 |
| - | - | - |
| androidx.annotation:annotation:1.3.0 | Apache 2.0 | 使用 `@Nullable` `@NotNull` |
| androidx.constraintlayout:constraintlayout:1.1.3 | Apache 2.0 | 使用 ConstraintLayout 进行布局 |
| androidx.core:core:1.7.0 | Apache 2.0 | 使用 `androidx.core.content.FileProvider` |
| androidx.databinding:viewbinding:7.2.2 | Apache 2.0 | 使用 ViewBinding 开发范式操作 UI |
| androidx.dynamicanimation:dynamicanimation-ktx:1.0.0-alpha03 | Apache 2.0 | UI 动画 |
| androidx.exifinterface:exifinterface:1.1.0 | Apache 2.0 | 读取相片信息 |
| androidx.fragment:fragment:1.3.6 | Apache 2.0 | 使用 Fragment |
| androidx.legacy:legacy-support-v4:1.0.0 | Apache 2.0 | 支持旧 Android API 接口 | 
| androidx.lifecycle:lifecycle-common:2.3.1 | Apache 2.0 | 使用 Lifecycle 接口 |
| androidx.lifecycle:lifecycle-extensions:2.0.0 | Apache 2.0 | 使用 Lifecycle 接口 |
| androidx.lifecycle:lifecycle-runtime-ktx:2.3.1 | Apache 2.0 | 使用 Lifecycle 接口 |
| androidx.media:media:1.5.0 | Apache 2.0 | MediaBrowserService 开发使用 |
| androidx.multidex:multidex:2.0.1 | Apache 2.0 | 通过 multidex 解决 dex 代码体积过大问题 |
| androidx.preference:preference:1.0.0 | Apache 2.0 | 支持设置页面 UI |
| androidx.recyclerview:recyclerview:1.1.0 | Apache 2.0 | 使用 RecyclerView 渲染 UI |
| androidx.viewpager2:viewpager2:1.0.0 | Apache 2.0 | 使用 ViewPager2 渲染 UI |
| androidx.viewpager:viewpager:1.0.0 | Apache 2.0 | 使用 ViewPager 渲染 UI |
| androidx.webkit:webkit:1.5.0 | Apache 2.0 | 使用 WebView 组件 |
| com.getkeepsafe.relinker:relinker:1.4.3 | Apache 2.0 | so 加载器 |
| com.github.bumptech.glide:glide:4.10.0 | Apache 2.0 | 使用 Glide 渲染图片 |
| com.google.code.gson:gson:2.8.9 | Apache 2.0 | 解析 Json |
| com.google.protobuf:protobuf-javalite:3.11.0 | BSD 3-clause | 解析 protobuf |
| com.squareup.okhttp3:okhttp:3.12.13 | Apache 2.0 | 发送 HTTP 请求 |
| com.tencent.wcdb:wcdb-android:1.1-19 | BSD 3-clause | WCDB 数据库实现 |
| com.tencent:mmkv-static:1.3.3 | BSD 3-clause | MMKV KV 存储实现 |
| commons-io:commons-io:2.6 | Apache 2.0 | 读写文件 |
| commons-lang:commons-lang:2.6 | Apache 2.0 | 开发使用 |
| io.reactivex:rxjava:1.1.7 | Apache 2.0 | 开发使用 |
| org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.10 | Apache 2.0 | Kotlin 开发使用 |
| org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10 | Apache 2.0 | Kotlin 开发使用 |
| org.jetbrains.kotlin:kotlin-stdlib:1.7.10 | Apache 2.0 | Kotlin 开发使用 |
| org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4 | Apache 2.0 | Kotlin Coroutine 开发使用 |
| org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4 | Apache 2.0 | Kotlin Coroutine 开发使用 |
| org.jooq:joor-java-6:0.9.7 | Apache 2.0 | 开发使用 |
| org.json:json:20211205 | Public | 解析 JSON |
