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

多设备权限与资源差异治理

将一个按钮隐藏在特定终端,确实能避免部分错误,却也容易形成新的维护问题:随着产品增加电脑端和折叠屏端,分散在页面里的设备类型判断会越来越多。更稳妥的处理方式是让页面只消费一份“功能可用性结果”,把权限声明、用户授权、系统能力、资源选择放到不同层次管理。

四个问题不要混在一个布尔值里

工程里经常出现 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 是否完整。

检查场景预期业务行为重点观察点
缺少相机能力保留文件选择入口避免功能全部消失
拒绝相机访问不进入采集流程拒绝状态有可理解的反馈
缺少平板专属素材读取通用资源不出现空白图标
网络中断能返回任务列表错误信息与用户操作一致
窗口缩放已选任务继续保留组件状态不被资源切换重置

经过这一层拆分,第三篇形成的工程结构是“配置负责声明、系统负责授权、能力检测负责判断、业务服务负责操作、资源系统负责匹配”。它并不是为每类设备维护一套应用,而是把确实存在差异的部分显式隔离。下一篇可以继续沿用这份任务中心工程,梳理发布包配置、版本信息、合规检查与跨端回归步骤。

相关文档

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐