8***@qq.com
8***@qq.com
  • 发布:2025-11-05 14:35
  • 更新:2025-11-05 14:35
  • 阅读:62

鸿蒙 UTS 插件开发实战:屏幕方向控制插件的完整实现

分类:鸿蒙Next

一、插件开发背景

在移动应用开发中,屏幕方向控制是一个常见且重要的功能需求

本文将详细介绍如何开发一个完整的鸿蒙屏幕方向控制 UTS 插件,包括原生 API 的使用、UTS 封装的实现细节以及最佳实践。

二、鸿蒙原生实现分析

2.1 鸿蒙屏幕方向 API 概述

鸿蒙系统提供了完善的窗口管理能力,屏幕方向控制主要通过 @ohos.window 模块实现。核心 API 包括:

  1. window.Orientation 枚举:定义了所有可用的屏幕方向
  2. setPreferredOrientation() 方法:设置窗口的首选显示方向
  3. getPreferredOrientation() 方法:获取当前窗口的显示方向

2.2 window.Orientation 枚举值详解

enum Orientation {  
  UNSPECIFIED = 0,           // 未指定方向  
  PORTRAIT = 1,              // 竖屏  
  LANDSCAPE = 2,             // 横屏  
  PORTRAIT_INVERTED = 3,     // 反向竖屏  
  LANDSCAPE_INVERTED = 4,    // 反向横屏  
  AUTO_ROTATION = 5,         // 自动旋转(跟随传感器)  
  AUTO_ROTATION_PORTRAIT = 6,      // 自动旋转(仅竖屏)  
  AUTO_ROTATION_LANDSCAPE = 7,     // 自动旋转(仅横屏)  
  AUTO_ROTATION_RESTRICTED = 8,    // 受限自动旋转  
  AUTO_ROTATION_PORTRAIT_RESTRICTED = 9,   // 受限自动旋转(仅竖屏)  
  AUTO_ROTATION_LANDSCAPE_RESTRICTED = 10  // 受限自动旋转(仅横屏)  
}

2.3 原生 ArkTS 实现示例

在纯鸿蒙应用中,屏幕方向控制的典型实现如下:

import window from '@ohos.window';  
import { BusinessError } from '@kit.BasicServicesKit';  

// 获取窗口实例  
let windowClass: window.Window = window.getLastWindow(context);  

// 设置为横屏模式  
let orientation = window.Orientation.LANDSCAPE;  
try {  
  windowClass.setPreferredOrientation(orientation, (err: BusinessError) => {  
    if (err.code) {  
      console.error('Failed to set window orientation. Cause: ' + JSON.stringify(err));  
      return;  
    }  
    console.info('Succeeded in setting window orientation.');  
  });  
} catch (exception) {  
  console.error('Failed to set window orientation. Cause: ' + JSON.stringify(exception));  
}

2.4 原生实现的关键点

  1. 窗口实例获取:必须先获取有效的 window 实例才能进行方向设置
  2. 异步回调处理:setPreferredOrientation 采用异步回调模式,需要正确处理成功和失败情况
  3. 异常捕获:需要使用 try-catch 捕获可能的运行时异常
  4. 错误码处理:回调函数中的 err.code 需要被正确检查

三、UTS 封装实现详解

3.1 插件目录结构设计

一个规范的 UTS 插件应该具有清晰的目录结构,便于代码复用和跨平台扩展:

uni_modules/harmony-screen-orientation/  
├── utssdk/  
│   ├── interface.uts          # 跨平台类型定义  
│   ├── unierror.uts           # 统一错误码定义  
│   └── app-harmony/           # 鸿蒙平台实现  
│       └── index.uts          # 主要逻辑实现  
├── package.json               # 插件元数据  
└── readme.md                  # 使用文档

3.2 类型系统设计(interface.uts)

良好的类型定义是 UTS 插件开发的基础。我们需要定义用户友好的接口类型:

import { ScreenOrientationErrorCode } from './unierror.uts'  

/**  
 * 屏幕方向类型  
 * 使用简单的字符串字面量类型,降低用户使用门槛  
 */  
export type ScreenOrientationType = 'portrait' | 'landscape' | 'auto' | 'portrait-reverse' | 'landscape-reverse'  

/**  
 * 设置屏幕方向参数定义  
 * 遵循 uni-app 统一的 API 风格  
 */  
export type SetScreenOrientationOptions = {  
    orientation: ScreenOrientationType  
    success?: SetScreenOrientationSuccessCallback | null  
    fail?: ScreenOrientationFailCallback | null  
    complete?: ScreenOrientationCompleteCallback | null  
}  

/**  
 * 获取屏幕方向参数定义  
 */  
export type GetScreenOrientationOptions = {  
    success?: GetScreenOrientationSuccessCallback | null  
    fail?: ScreenOrientationFailCallback | null  
    complete?: ScreenOrientationCompleteCallback | null  
}

设计要点:

  1. 简化类型名称:使用 'portrait''landscape' 等简单字符串,而非暴露鸿蒙原生的 window.Orientation 枚举
  2. 统一回调风格:采用 successfailcomplete 三段式回调,与 uni-app 生态保持一致
  3. 可选参数设计:所有回调函数都是可选的,增强使用灵活性

3.3 错误码体系设计(unierror.uts)

完善的错误处理机制能够帮助开发者快速定位问题:

import { IScreenOrientationError } from './interface.uts'  

/**  
 * 错误码定义  
 * 13xxx 段作为屏幕方向相关错误  
 */  
export type ScreenOrientationErrorCode =  
    13001 |  // 系统不支持  
    13002 |  // 无效的屏幕方向参数  
    13003 |  // 设置屏幕方向失败  
    13004    // 获取窗口对象失败  

/**  
 * 错误主题  
 */  
export const UniErrorSubject = 'uni-screen-orientation'  

/**  
 * 错误信息映射表  
 */  
export const ScreenOrientationErrorMessages: Map<ScreenOrientationErrorCode, string> = new Map([  
    [13001, '系统不支持'],  
    [13002, '无效的屏幕方向参数'],  
    [13003, '设置屏幕方向失败'],  
    [13004, '获取窗口对象失败']  
])  

/**  
 * 错误实现类  
 */  
export class ScreenOrientationErrorImpl extends UniError implements IScreenOrientationError {  
    override errCode: ScreenOrientationErrorCode  

    constructor(errCode: ScreenOrientationErrorCode) {  
        super()  
        this.errSubject = UniErrorSubject  
        this.errCode = errCode  
        this.errMsg = ScreenOrientationErrorMessages.get(errCode) ?? ''  
    }  
}

设计要点:

  1. 错误码分段管理:使用 13xxx 段,避免与其他插件冲突
  2. 错误信息集中管理:通过 Map 结构统一维护错误信息
  3. 继承 UniError 基类:保持与 uni-app 错误体系的兼容性

3.4 核心逻辑实现(app-harmony/index.uts)

3.4.1 类型映射机制

UTS 封装的核心是建立用户友好类型与原生类型之间的映射关系:

import window from '@ohos.window'  

/**  
 * 屏幕方向映射表:用户类型 → 原生类型  
 * 将简单的字符串映射到鸿蒙的 window.Orientation 枚举  
 */  
const OrientationMap: Map<ScreenOrientationType, window.Orientation> = new Map([  
    ['portrait', window.Orientation.PORTRAIT],  
    ['landscape', window.Orientation.LANDSCAPE],  
    ['auto', window.Orientation.AUTO_ROTATION],  
    ['portrait-reverse', window.Orientation.PORTRAIT_INVERTED],  
    ['landscape-reverse', window.Orientation.LANDSCAPE_INVERTED]  
])  

/**  
 * 反向映射表:原生类型 → 用户类型  
 * 用于将鸿蒙返回的枚举值转换为用户友好的字符串  
 */  
const ReverseOrientationMap: Map<window.Orientation, ScreenOrientationType> = new Map([  
    [window.Orientation.PORTRAIT, 'portrait'],  
    [window.Orientation.LANDSCAPE, 'landscape'],  
    [window.Orientation.AUTO_ROTATION, 'auto'],  
    [window.Orientation.PORTRAIT_INVERTED, 'portrait-reverse'],  
    [window.Orientation.LANDSCAPE_INVERTED, 'landscape-reverse']  
])

3.4.2 setScreenOrientation 实现

export const setScreenOrientation: SetScreenOrientation = function (options: SetScreenOrientationOptions) {  
    // 第一步:参数验证  
    const orientation = OrientationMap.get(options.orientation)  
    if (orientation == null) {  
        const err = new ScreenOrientationErrorImpl(13002)  
        options.fail?.(err)  
        options.complete?.(err)  
        return  
    }  

    try {  
        // 第二步:获取窗口实例  
        // UTSHarmony.getCurrentWindow() 是 UTS 提供的全局 API  
        const windowInstance = UTSHarmony.getCurrentWindow()  
        if (windowInstance == null) {  
            const err = new ScreenOrientationErrorImpl(13004)  
            options.fail?.(err)  
            options.complete?.(err)  
            return  
        }  

        // 第三步:调用原生 API 设置方向  
        windowInstance.setPreferredOrientation(orientation, (err) => {  
            if (err != null && err.code != 0) {  
                // 设置失败  
                const error = new ScreenOrientationErrorImpl(13003)  
                options.fail?.(error)  
                options.complete?.(error)  
                return  
            }  

            // 设置成功  
            const res: SetScreenOrientationSuccess = {  
                errMsg: 'setScreenOrientation:ok'  
            }  
            options.success?.(res)  
            options.complete?.(res)  
        })  
    } catch (e) {  
        // 捕获异常  
        const err = new ScreenOrientationErrorImpl(13003)  
        options.fail?.(err)  
        options.complete?.(err)  
    }  
}

实现要点分析:

  1. 参数验证前置:在调用原生 API 之前先验证参数合法性,快速失败
  2. 使用 UTSHarmony 全局 APIUTSHarmony.getCurrentWindow() 是 UTS 框架提供的便捷方法,简化了窗口实例获取
  3. 完整的错误处理:覆盖参数错误、窗口获取失败、设置失败和异常捕获四种情况
  4. 回调时机准确:success 和 fail 互斥,complete 总是执行

3.4.3 getScreenOrientation 实现

export const getScreenOrientation: GetScreenOrientation = function (options?: GetScreenOrientationOptions | null) {  
    try {  
        // 第一步:获取窗口实例  
        const windowInstance = UTSHarmony.getCurrentWindow()  
        if (windowInstance == null) {  
            const err = new ScreenOrientationErrorImpl(13004)  
            options?.fail?.(err)  
            options?.complete?.(err)  
            return  
        }  

        // 第二步:获取当前方向  
        const currentOrientation = windowInstance.getPreferredOrientation()  

        // 第三步:类型转换  
        const orientationType = ReverseOrientationMap.get(currentOrientation) ?? 'portrait'  

        // 第四步:返回结果  
        const res: GetScreenOrientationSuccess = {  
            orientation: orientationType,  
            errMsg: 'getScreenOrientation:ok'  
        }  
        options?.success?.(res)  
        options?.complete?.(res)  
    } catch (e) {  
        const err = new ScreenOrientationErrorImpl(13003)  
        options?.fail?.(err)  
        options?.complete?.(err)  
    }  
}

实现要点分析:

  1. 可选参数处理:使用可选链操作符 ?. 处理可能为空的 options 参数
  2. 反向映射应用:使用 ReverseOrientationMap 将原生枚举转换为用户友好的字符串
  3. 默认值保护:使用空值合并运算符 ?? 提供默认值,防止未知枚举导致的问题

3.5 UTS 全局 API 的应用

在本插件中,我们使用了 UTS 框架提供的 UTSHarmony.getCurrentWindow() 全局 API。这个 API 封装了获取当前窗口实例的复杂逻辑,开发者无需关心 context 的获取和管理。

相比原生 ArkTS 实现,UTS 方式的优势:

// 原生 ArkTS 方式(需要 context)  
let context = getContext(this) as common.UIAbilityContext;  
let windowClass = window.getLastWindow(context);  

// UTS 方式(无需 context)  
const windowInstance = UTSHarmony.getCurrentWindow()

四、用户使用说明

4.1 插件安装

将插件复制到项目的 uni_modules 目录下:

your-project/  
└── uni_modules/  
    └── harmony-screen-orientation/

4.2 基础使用示例

4.2.1 设置为横屏模式

<template>  
  <view class="container">  
    <button @click="setLandscape">切换到横屏</button>  
  </view>  
</template>  

<script setup lang="ts">  
import { setScreenOrientation } from "@/uni_modules/harmony-screen-orientation"  

const setLandscape = () => {  
  setScreenOrientation({  
    orientation: 'landscape',  
    success: (res) => {  
      console.log('横屏设置成功', res)  
      uni.showToast({  
        title: '已切换到横屏',  
        icon: 'success'  
      })  
    },  
    fail: (err) => {  
      console.error('横屏设置失败', err)  
      uni.showToast({  
        title: `设置失败: ${err.errMsg}`,  
        icon: 'none'  
      })  
    }  
  })  
}  
</script>

4.2.2 设置为自动旋转

import { setScreenOrientation } from "@/uni_modules/harmony-screen-orientation"  

// 启用自动旋转(需要系统设置中开启自动旋转)  
setScreenOrientation({  
  orientation: 'auto',  
  success: () => {  
    console.log('自动旋转已启用')  
  }  
})

4.2.3 获取当前屏幕方向

<template>  
  <view class="container">  
    <text>当前方向: {{ currentOrientation }}</text>  
    <button @click="checkOrientation">检查方向</button>  
  </view>  
</template>  

<script setup lang="ts">  
import { ref } from 'vue'  
import { getScreenOrientation } from "@/uni_modules/harmony-screen-orientation"  

const currentOrientation = ref<string>('未知')  

const checkOrientation = () => {  
  getScreenOrientation({  
    success: (res) => {  
      currentOrientation.value = res.orientation  
      console.log('当前屏幕方向:', res.orientation)  
    }  
  })  
}  
</script>

错误处理最佳实践

import { setScreenOrientation } from "@/uni_modules/harmony-screen-orientation"  
import type { IScreenOrientationError } from "@/uni_modules/harmony-screen-orientation"  

const handleOrientationChange = (orientation: string) => {  
  setScreenOrientation({  
    orientation: orientation as any,  
    success: (res) => {  
      console.log('方向切换成功:', res)  
    },  
    fail: (err: IScreenOrientationError) => {  
      // 根据错误码进行不同处理  
      switch (err.errCode) {  
        case 13002:  
          console.error('参数错误,请检查 orientation 值')  
          break  
        case 13003:  
          console.error('设置失败,可能是系统限制')  
          break  
        case 13004:  
          console.error('无法获取窗口,请稍后重试')  
          break  
        default:  
          console.error('未知错误:', err.errMsg)  
      }  
    },  
    complete: () => {  
      console.log('操作完成')  
    }  
  })  
}

TypeScript 类型支持

插件提供完整的 TypeScript 类型定义,享受类型提示和类型检查:

import {   
  setScreenOrientation,   
  getScreenOrientation,  
  type SetScreenOrientationOptions,  
  type GetScreenOrientationOptions,  
  type ScreenOrientationType   
} from "@/uni_modules/harmony-screen-orientation"  

// 类型安全的参数定义  
const options: SetScreenOrientationOptions = {  
  orientation: 'landscape', // 类型提示可用值  
  success: (res) => {  
    // res 参数类型自动推导  
    console.log(res.errMsg)  
  }  
}  

setScreenOrientation(options)

学习资源

关注我

如果本文对你有帮助,欢迎点赞

3 关注 分享
DCloud_CHB DCloud_UNI_CHB MakeUp

要回复文章请先登录注册