HarmonyOS 7 多设备协同:权限与资源差异治理(连载03-03)【共创稿事节】
同一套“工作任务中心”在手机、平板与电脑上打开,列表、详情和键盘焦点可以沿用共同的业务逻辑;但当用户点击“拍摄附件”“选择图片”或“打开在线协作文档”,不同终端的可用设备、权限状态以及资源目录会直接影响操作结果。前两篇处理了断点布局和键鼠焦点,这一篇进一步把适配范围推进到功能入口:界面能够出现,不等于对应功能已经具备执行条件。

将一个按钮隐藏在特定终端,确实能避免部分错误,却也容易形成新的维护问题:随着产品增加电脑端和折叠屏端,分散在页面里的设备类型判断会越来越多。更稳妥的处理方式是让页面只消费一份“功能可用性结果”,把权限声明、用户授权、系统能力、资源选择放到不同层次管理。
四个问题不要混在一个布尔值里
工程里经常出现 canUseCamera = true 这样的字段。它到底表示设备存在相机、应用已经申请权限、用户允许访问,还是当前业务允许拍摄?如果四种含义共享同一个变量,后续排查会很困难。建议把条件拆为四个独立维度。
| 维度 | 判断发生的时机 | 具体处理 |
|---|---|---|
| 系统能力 | 进入功能前 | 检查相关 SysCap 是否可用,必要时切换替代路径 |
| 权限声明 | 构建配置阶段 | 在 module.json5 中只列出确实使用的权限 |
| 用户授权 | 点击敏感功能时 | 按权限类型处理授权结果及拒绝结果 |
| 业务条件 | 每次请求前 | 检查任务状态、角色权限和附件数量限制 |
例如“上传任务截图”并不天然需要相机权限:从系统照片选择器选取文件和调用相机采集是两条不同的路径。把两者区分开,产品既能减少多余授权弹窗,也便于在无相机的终端继续提供文件选择功能。业务角色权限与操作系统授权也不相等;前者由应用判断,后者由系统管理。
权限只声明真正需要的能力
对于任务中心的在线协作功能,网络访问是明确需求。项目需要在模块配置中声明网络权限,网络请求实现再交给相应的网络框架;无需为了“以后可能接入的功能”提前把联系人、定位、相机等权限全部加进去。下列片段展示 module.json5 中与网络访问相关的关键配置,其他模块字段继续保留工程原有值。
{
"module": {
"name": "entry",
"type": "entry",
"requestPermissions": [
{ "name": "ohos.permission.INTERNET" },
{ "name": "ohos.permission.CAMERA" }
]
}
}
INTERNET 属于按配置声明的常见权限,不应把它与需要用户确认的权限混为一类。配置中的 CAMERA 专门对应本应用的“直接拍照”入口;如果产品只支持系统文件选择,应同时删去这一声明及相关采集代码。对于需要用户确认的相机访问,可以在进入拍摄流程前请求 ohos.permission.CAMERA;拒绝后让用户返回附件选择入口,而不是不断弹出同一请求。负责显示的组件不直接处理授权细节,交由独立的服务类统一封装。
import { abilityAccessCtrl, common, Permissions } from '@kit.AbilityKit';
export class CapturePermissionService {
async requestCamera(context: common.UIAbilityContext): Promise<boolean> {
const permission: Permissions = 'ohos.permission.CAMERA';
const manager = abilityAccessCtrl.createAtManager();
try {
const result = await manager.requestPermissionsFromUser(
context, [permission]);
return result.authResults.length === 1 && result.authResults[0] === 0;
} catch (error) {
console.error(`requestCamera failed: ${JSON.stringify(error)}`);
return false;
}
}
}
这个封装故意只返回授权状态,没有在授权成功后立即打开相机。授权是一次条件判断,采集与文件保存是另一条业务链路:两者分开,便于在页面销毁、用户取消、重复点击时阻止多次执行。权限被拒绝时,应说明这项功能需要什么访问条件,并保留浏览既有附件、查看任务详情等不依赖该权限的操作。

能力判断比硬编码设备名称更可靠
“手机都有相机、电脑没有相机”这样的规则无法覆盖外接设备、不同产品形态及功能裁剪。同一个设备类型内也可能存在不同的系统能力。对依赖特定系统模块的接口,可以通过 SysCap 进行能力检查;得到支持结果以后仍需处理权限与执行异常。
export interface DeviceFeatures {
canPlayAudio: boolean;
canUseCamera: boolean;
}
export function detectDeviceFeatures(): DeviceFeatures {
return {
canPlayAudio: canIUse('SystemCapability.Multimedia.Audio.Core'),
canUseCamera: canIUse('SystemCapability.Multimedia.Camera.Core')
};
}
export function selectAttachmentEntry(features: DeviceFeatures,
isCameraAuthorized: boolean): string {
if (features.canUseCamera && isCameraAuthorized) {
return '拍摄或从文件选择';
}
return '从文件选择';
}
需要注意,canIUse() 表示对应系统能力是否存在,不能直接替代授权检查。上面的“拍摄或从文件选择”是界面策略,不负责申请权限;真正的拍摄执行仍应捕获接口返回的错误。对于不同 API 版本的接口,构建时还应检查 SDK 声明与目标设备支持范围。
资源差异不是复制整套页面
适配过程中另一个容易被忽视的问题是资源包。手机端为了减少拥挤使用精简图标,平板端使用更宽的任务插画,若两个资源都放在页面里按设备类型切换,逻辑会直接侵入组件。HarmonyOS 的资源限定词目录允许根据设备配置选择对应资源,因此可以让同一个资源名称在不同终端使用不同素材。
entry/src/main/resources/
├── base/
│ └── media/task_banner.png
├── phone/
│ └── media/task_banner.png
└── tablet/
└── media/task_banner.png
@Entry
@Component
struct ResourceTaskPage {
@State selectedTitle: string = '需求评审';
build() {
Column({ space: 16 }) {
Text('工作任务中心').fontSize(26).fontWeight(FontWeight.Bold);
Image($r('app.media.task_banner'))
.width('100%')
.height(180)
.objectFit(ImageFit.Contain);
Text(this.selectedTitle).fontSize(18);
Button('查看任务')
.onClick(() => this.selectedTitle = '版本发布');
}
.padding(20)
.width('100%');
}
}
同名图片的使用让 UI 不必关心实际选择了哪个限定词目录,但 base 必须保留完整的兜底资源。否则当某种设备没有匹配的专属目录时,可能取不到预期图标。涉及应用桌面图标时,还需检查 AppScope 和模块内的资源位置,不能仅凭页面图片显示正常就认为所有图标配置完整。资源匹配解决的是素材差异;文字布局、键鼠焦点和窗口断点,仍然沿用前两篇的 UI 适配方案。
从“允许访问”到“操作完成”的闭环
假设用户在平板任务详情中按下“添加附件”,可以按以下顺序组织:先显示“选择现有文件”和“拍摄照片”两个入口;当设备不具备拍摄能力时,将拍摄入口替换为清晰的文字说明;选择拍摄时才检查和申请权限;授权成功后进入采集流程;最终将获得的附件统一交给任务上传服务。这样同一份任务列表和附件数据模型不需要随着终端发生分叉。
出错提示也应该区分来源。网络超时提示重新连接,照片访问被拒绝提供重新授权入口,文件格式不支持提示可接受的类型,而任务没有编辑权限则解释当前状态。不同错误不应该都显示成“设备不支持”。在日志里记录操作阶段与经过脱敏的错误类别即可,避免输出真实附件路径、用户身份信息或授权令牌。

发布前应覆盖的跨设备检查
可以以功能链路而非设备型号组织检查:检查手机和宽屏设备是否都能进入任务列表,拒绝相机授权以后文件选择是否仍可用,网络断开后详情能否保留已加载内容,切换浅深色模式以后图标是否仍然可辨,宽屏窗口缩窄以后按钮有无被裁切。特别是资源限定词,既要查 phone、tablet 是否齐全,还要查 base 是否完整。
| 检查场景 | 预期业务行为 | 重点观察点 |
|---|---|---|
| 缺少相机能力 | 保留文件选择入口 | 避免功能全部消失 |
| 拒绝相机访问 | 不进入采集流程 | 拒绝状态有可理解的反馈 |
| 缺少平板专属素材 | 读取通用资源 | 不出现空白图标 |
| 网络中断 | 能返回任务列表 | 错误信息与用户操作一致 |
| 窗口缩放 | 已选任务继续保留 | 组件状态不被资源切换重置 |
经过这一层拆分,第三篇形成的工程结构是“配置负责声明、系统负责授权、能力检测负责判断、业务服务负责操作、资源系统负责匹配”。它并不是为每类设备维护一套应用,而是把确实存在差异的部分显式隔离。下一篇可以继续沿用这份任务中心工程,梳理发布包配置、版本信息、合规检查与跨端回归步骤。
相关文档
更多推荐
所有评论(0)