HarmonyOS 开发指南:系统API调用与兼容性处理实战
项目概述
本示例项目旨在演示 HarmonyOS 应用开发中如何高效集成各类系统级能力。通过具体的代码实现,展示了应用与系统服务的交互方式,涵盖了身份识别、意图跳转、多媒体调用、网络监控以及安全隐私保护等核心场景。
关键技术要点
1. 应用匿名标识符 (AAID) 的生命周期
在获取 AAID 时需注意其持久性特征。经测试验证,当用户完全卸载应用并重新安装后,系统生成的 AAID 值会发生变更。若业务逻辑需要标识符在重装后保持不变,建议引入如 harmony-utils 等第三方库或采用服务端存储方案来实现跨周期的用户唯一性识别。
2. 窗口隐私保护机制
启用隐私模式(防截屏/录屏)是保护敏感数据的重要手段。当该模式激活时,系统会拦截用户的截屏操作并弹出"当前页面涉及隐私内容"的提示。对于录屏行为,被保护页面的内容将显示为黑屏,从而有效防止敏感信息泄露。
3. API 兼容性检测
由于 HarmonyOS 设备形态多样,部分 API 并非在所有设备上通用。开发中若遇到 IDE 提示"The API is not supported on all devices",必须结合 canIUse 方法进行运行时能力检测。
实现步骤如下:
- 查阅文档:确认目标 API 是否存在设备限制。
- 定位系统能力:找到对应的 SystemCapability(例如
SystemCapability.Telephony.Call)。 - 条件执行:在调用逻辑前增加判断分支。
以下代码演示了在拨打电话前进行能力检测的安全做法:
import { call } from '@kit.TelephonyKit';
import { promptAction } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';
// 定义系统能力常量
const CAP_TELEPHONY_CALL = 'SystemCapability.Telephony.Call';
function attemptMakeCall phoneNumber: string) {
if (canIUse(CAP_TELEPHONY_CALL)) {
call.makeCall(phoneNumber, (err: BusinessError) => {
if (err) {
console.error(`拨号失败: ${JSON.stringify(err)}`);
} else {
console.log('拨号成功');
}
});
} else {
promptAction.showToast({
message: '当前设备不支持电话功能',
duration: 2000
});
}
}
完整代码实现
以下代码重构了原有逻辑,优化了变量命名与结构,并封装了各类功能的调用入口。
import { bundleManager, common, Want } from '@kit.AbilityKit';
import { BusinessError, deviceInfo } from '@kit.BasicServicesKit';
import { call } from '@kit.TelephonyKit';
import { scanBarcode, scanCore } from '@kit.ScanKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { promptAction, window } from '@kit.ArkUI';
import { connection } from '@kit.NetworkKit';
import { camera, cameraPicker } from '@kit.CameraKit';
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { resourceManager } from '@kit.LocalizationKit';
import { AAID } from '@kit.PushKit';
// 定义功能菜单项的数据结构
interface FeatureMenu {
label: string;
action: Want | (ctx: common.UIAbilityContext) => void;
}
// --- 意图构造器 ---
function buildSmsIntent(): Want {
return {
bundleName: 'com.ohos.mms',
abilityName: 'com.ohos.mms.MainAbility',
parameters: {
contactObjects: JSON.stringify([{ contactsName: 'LiSi', telephone: '13900001111' }]),
content: ' HarmonyOS 测试短信',
pageFlag: 'conversation'
}
};
}
function buildWebIntent(): Want {
return {
action: 'ohos.want.action.viewData',
entities: ['entity.system.browsable'],
uri: 'https://developer.huawei.com'
};
}
function buildAppStoreIntent(): Want {
const targetBundle = "com.example.app";
return {
action: 'ohos.want.action.appdetail',
uri: `store://appgallery.huawei.com/app/detail?id=${targetBundle}`,
};
}
function buildSettingsIntent(uri: string): Want {
return {
bundleName: 'com.huawei.hmos.settings',
abilityName: 'com.huawei.hmos.settings.MainAbility',
uri: uri
};
}
// --- 业务逻辑函数 ---
function handleCall() {
const CAPABILITY = 'SystemCapability.Telephony.Call';
if (canIUse(CAPABILITY)) {
call.makeCall("13800138000", (err: BusinessError) => {
if (err) {
console.error(`Call failed: ${JSON.stringify(err)}`);
} else {
console.log('Call initiated');
}
});
} else {
promptAction.showToast({ message: '设备不支持通话功能', duration: 2000 });
}
}
function handleScan(context: common.UIAbilityContext) {
const SCAN_CAP = 'SystemCapability.Multimedia.Scan.ScanBarcode';
const CORE_CAP = 'SystemCapability.Multimedia.Scan.Core';
if (canIUse(SCAN_CAP) && canIUse(CORE_CAP)) {
const scanOptions: scanBarcode.ScanOptions = {
scanTypes: [scanCore.ScanType.ALL],
enableMultiMode: true,
enableAlbum: true
};
scanBarcode.startScanForResult(context, scanOptions, (error: BusinessError, result: scanBarcode.ScanResult) => {
if (error) {
hilog.error(0x0001, 'ScanDemo', `Scan error: ${error.message}`);
return;
}
hilog.info(0x0001, 'ScanDemo', `Result: ${JSON.stringify(result)}`);
promptAction.showToast({ message: `扫码结果: ${result.originalValue}`, duration: 2000 });
});
} else {
promptAction.showToast({ message: '设备不支持扫码', duration: 2000 });
}
}
function checkAppInstallation() {
try {
// 测试高德地图链接
const testLink = "amapuri://";
const isInstalled = bundleManager.canOpenLink(testLink);
const msg = isInstalled ? "应用已安装" : "应用未安装";
promptAction.showToast({ message: msg, duration: 2000 });
} catch (err) {
const error = err as BusinessError;
if (error.code === 17700056) {
promptAction.showToast({ message: '请在 module.json5 中配置 querySchemes', duration: 2000 });
}
}
}
function showAppInfo() {
const flags = bundleManager.BundleFlag.GET_BUNDLE_INFO_DEFAULT |
bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION;
const info = bundleManager.getBundleInfoForSelfSync(flags);
// 简化展示,仅打印日志
console.info('App Info:', JSON.stringify(info));
promptAction.showToast({ message: `包名: ${info.name}`, duration: 2000 });
}
function showDeviceInfo() {
const infoStr = `品牌: ${deviceInfo.brand}\n型号: ${deviceInfo.productSeries}\nAPI: ${deviceInfo.sdkApiVersion}`;
promptAction.showToast({ message: infoStr, duration: 3000 });
}
async function togglePrivacyMode(enable: boolean, context: common.UIAbilityContext) {
try {
const windowStage = await window.getLastWindow(context);
windowStage.setWindowPrivacyMode(enable, (err: BusinessError) => {
if (err.code) {
console.error(`Set privacy mode failed: ${JSON.stringify(err)}`);
if (err.code === 201) {
promptAction.showToast({ message: '缺少权限: ohos.permission.PRIVACY_WINDOW', duration: 2000 });
}
return;
}
const status = enable ? "开启" : "关闭";
promptAction.showToast({ message: `已${status}防截屏`, duration: 2000 });
});
} catch (e) {
console.error(`Exception: ${JSON.stringify(e)}`);
}
}
function monitorNetworkStatus() {
const netConn = connection.createNetConnection();
netConn.register((err: BusinessError) => {
if (err) {
console.error(`Network register fail: ${err.code}`);
return;
}
promptAction.showToast({ message: '开始监听网络', duration: 2000 });
});
netConn.on('netLost', () => {
promptAction.showToast({ message: '网络已断开', duration: 2000 });
});
netConn.on('netConnectionPropertiesChange', () => {
promptAction.showToast({ message: '网络状态变更', duration: 2000 });
});
}
async function capturePhoto(context: common.UIAbilityContext) {
try {
const profile: cameraPicker.PickerProfile = {
cameraPosition: camera.CameraPosition.CAMERA_POSITION_BACK
};
const result = await cameraPicker.pick(context, [cameraPicker.PickerMediaType.PHOTO], profile);
if (result.resultCode === 0) {
context.eventHub.emit("imageUpdate", result.resultUri);
}
} catch (err) {
console.error('Camera error', JSON.stringify(err));
}
}
function pickGalleryImage(context: common.UIAbilityContext) {
try {
const options = new photoAccessHelper.PhotoSelectOptions();
options.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE;
options.maxSelectNumber = 1;
const picker = new photoAccessHelper.PhotoViewPicker();
picker.select(options).then((res: photoAccessHelper.PhotoSelectResult) => {
if (res.photoUris && res.photoUris.length > 0) {
context.eventHub.emit("imageUpdate", res.photoUris[0]);
}
}).catch((err: BusinessError) => {
console.error('Gallery error', err.message);
});
} catch (e) {
console.error('Pick exception', JSON.stringify(e));
}
}
function setScreenOrientation(orientation: window.Orientation) {
window.getLastWindow(getContext()).then((win) => {
win.setPreferredOrientation(orientation);
});
}
function getCurrentOrientation() {
const config = getContext().resourceManager.getConfigurationSync();
const isPortrait = config.direction === resourceManager.Direction.DIRECTION_VERTICAL;
promptAction.showToast({ message: isPortrait ? "当前为竖屏" : "当前为横屏", duration: 2000 });
}
function showDeviceType() {
const type = getContext().resourceManager.getDeviceCapabilitySync().deviceType;
let typeStr = "未知设备";
switch (type) {
case resourceManager.DeviceType.DEVICE_TYPE_PHONE: typeStr = "手机"; break;
case resourceManager.DeviceType.DEVICE_TYPE_TABLET: typeStr = "平板"; break;
case resourceManager.DeviceType.DEVICE_TYPE_TV: typeStr = "电视"; break;
// ... 其他类型
}
promptAction.showToast({ message: typeStr, duration: 2000 });
}
function getLocalIp() {
connection.getDefaultNet().then((handle: connection.NetHandle) => {
connection.getConnectionProperties(handle, (err, data) => {
if (!err && data.linkAddresses.length > 0) {
const ip = data.linkAddresses[0].address.address;
promptAction.showToast({ message: `IP地址: ${ip}`, duration: 2000 });
}
});
});
}
function fetchAAID() {
AAID.getAAID().then((id: string) => {
promptAction.showToast({ message: `AAID: ${id}`, duration: 3000 });
});
}
// --- UI 入口 ---
@Entry
@Component
struct SystemApiDemo {
@State menuList: FeatureMenu[] = [];
@State previewUri: string = "";
aboutToAppear(): void {
// 使用 EventHub 接收图片选择结果
getContext(this).eventHub.on('imageUpdate', (uri: string) => {
this.previewUri = uri;
});
// 初始化功能列表
this.menuList = [
{ label: '获取设备 AAID', action: fetchAAID },
{ label: '发送短信', action: buildSmsIntent() },
{ label: '打开浏览器', action: buildWebIntent() },
{ label: '跳转应用市场', action: buildAppStoreIntent() },
{ label: 'WLAN 设置', action: buildSettingsIntent('wifi_entry') },
{ label: '输入法设置', action: buildSettingsIntent('set_input') },
{ label: '拨打电话', action: handleCall },
{ label: '扫一扫', action: handleScan },
{ label: '检测应用安装', action: checkAppInstallation },
{ label: '应用信息', action: showAppInfo },
{ label: '设备信息', action: showDeviceInfo },
{ label: '开启防截屏', action: (ctx) => togglePrivacyMode(true, ctx) },
{ label: '关闭防截屏', action: (ctx) => togglePrivacyMode(false, ctx) },
{ label: '监听网络', action: monitorNetworkStatus },
{ label: '获取本机IP', action: getLocalIp },
{ label: '拍照', action: capturePhoto },
{ label: '选择图片', action: pickGalleryImage },
{ label: '设为竖屏', action: () => setScreenOrientation(window.Orientation.PORTRAIT) },
{ label: '设为横屏', action: () => setScreenOrientation(window.Orientation.LANDSCAPE) },
{ label: '屏幕方向检测', action: getCurrentOrientation },
{ label: '设备类型', action: showDeviceType }
];
}
build() {
Stack() {
List() {
ForEach(this.menuList, (item: FeatureMenu, index: number) => {
ListItem() {
Button(`${index + 1}. ${item.label}`)
.width('100%')
.onClick(() => {
if (typeof item.action === 'function') {
(item.action as Function)(getContext(this) as common.UIAbilityContext);
} else {
const want = item.action as Want;
const ctx = getContext(this) as common.UIAbilityContext;
ctx.startAbility(want).catch((err: BusinessError) => {
console.error(`Start Ability failed: ${err.code}`);
});
}
})
}
})
}
.width('100%')
.height('100%')
.alignListItem(ListItemAlign.Center)
// 图片预览浮层
if (this.previewUri) {
Column() {
Image(this.previewUri)
.width('80%')
.objectFit(ImageFit.Contain)
.border({ width: 1, color: Color.White })
}
.width('100%')
.height('100%')
.backgroundColor('rgba(0,0,0,0.8)')
.onClick(() => {
this.previewUri = "";
})
}
}
}
}