一、插件开发背景
在移动应用开发中,屏幕方向控制是一个常见且重要的功能需求
本文将详细介绍如何开发一个完整的鸿蒙屏幕方向控制 UTS 插件,包括原生 API 的使用、UTS 封装的实现细节以及最佳实践。
二、鸿蒙原生实现分析
2.1 鸿蒙屏幕方向 API 概述
鸿蒙系统提供了完善的窗口管理能力,屏幕方向控制主要通过 @ohos.window 模块实现。核心 API 包括:
- window.Orientation 枚举:定义了所有可用的屏幕方向
- setPreferredOrientation() 方法:设置窗口的首选显示方向
- 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 原生实现的关键点
- 窗口实例获取:必须先获取有效的 window 实例才能进行方向设置
- 异步回调处理:setPreferredOrientation 采用异步回调模式,需要正确处理成功和失败情况
- 异常捕获:需要使用 try-catch 捕获可能的运行时异常
- 错误码处理:回调函数中的 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
}
设计要点:
- 简化类型名称:使用
'portrait'、'landscape'等简单字符串,而非暴露鸿蒙原生的window.Orientation枚举 - 统一回调风格:采用
success、fail、complete三段式回调,与 uni-app 生态保持一致 - 可选参数设计:所有回调函数都是可选的,增强使用灵活性
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) ?? ''
}
}
设计要点:
- 错误码分段管理:使用 13xxx 段,避免与其他插件冲突
- 错误信息集中管理:通过 Map 结构统一维护错误信息
- 继承 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)
}
}
实现要点分析:
- 参数验证前置:在调用原生 API 之前先验证参数合法性,快速失败
- 使用 UTSHarmony 全局 API:
UTSHarmony.getCurrentWindow()是 UTS 框架提供的便捷方法,简化了窗口实例获取 - 完整的错误处理:覆盖参数错误、窗口获取失败、设置失败和异常捕获四种情况
- 回调时机准确: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)
}
}
实现要点分析:
- 可选参数处理:使用可选链操作符
?.处理可能为空的 options 参数 - 反向映射应用:使用 ReverseOrientationMap 将原生枚举转换为用户友好的字符串
- 默认值保护:使用空值合并运算符
??提供默认值,防止未知枚举导致的问题
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)
学习资源
关注我
如果本文对你有帮助,欢迎点赞
0 个评论
要回复文章请先登录或注册