【芙莉莲教你写代码】元服务 DevEco Studio 第一章 环境与示例
一,创建元服务项目
src > main > ets:用于存放ArkTS源码。
src > main > ets > entryability:元服务的入口。 -
src > main > ets > pages:元服务包含的页面。 -
src > main > resources:用于存放元服务所用到的资源文件,如图形、多媒体、字符串、布局文件等。关于资源文件, -
src > main > module.json5:模块配置文件。主要包含HAP的配置信息、元服务在具体设备上的配置信息以及元服务的全局配置信息。
build-profile.json5:当前的模块信息 、编译信息配置项,包括buildOption、targets配置等。
hvigorfile.ts:模块级编译构建任务脚本,开发者可以自定义相关任务和代码实现。
oh_modules:用于存放三方库依赖信息。
build-profile.json5:元服务级配置信息,包括签名signingConfigs、产品配置products等。
hvigorfile.ts:元服务级编译构建任务脚本。
二,生成元服务图标 添加Image Asset
图标格式:.png、.jpeg、.jpg格式的静态图片资源
图标尺寸:1024 x 1024 px (正方形)
图标背景:不透明
质量要求:图标内容需清晰可辨,避免存在模糊、锯齿、拉伸等问题。
Color:推荐使用的图标颜色。选择不同颜色,右边图标预览区域可查看相应的效果。
Name:生成的图标名称。
Res Directory:生成的512px*512px尺寸图标在工程中的保存位置。
Save to:生成的216px*216px尺寸图标需要指定本地文件夹的保存位置。后续在AppGallery Connect上架元服务时,需使用该图标。
点击OK,保存配置并在相应模块目录src > main > resources > base > media路径下生成元服务图标。可在模块级module.json5中的icon字段中配置元服务图标。 三,构建元服务的第一个页面 默认为相对布局的代码,布局的方式有很多种。
线性布局 (Row/Column),层叠布局 (Stack),弹性布局 (Flex),相对布局 (RelativeContainer),栅格布局 (GridRow/GridCol),媒体查询 (@ohos.mediaquery),创建列表 (List),创建网格 (Grid/GridItem),创建轮播 (Swiper),选项卡 (Tabs)。
这里我们先来看相对布局:
RelativeContainer为采用相对布局的容器,支持容器内部的子元素设置相对位置关系,适用于界面复杂场景的情况,对多个子组件进行对齐和排列。子元素支持指定兄弟元素作为锚点,也支持指定父容器作为锚点,基于锚点做相对位置布局。
示例代码 import { authentication } from '@kit.AccountKit'; import { BusinessError } from '@kit.BasicServicesKit'; import { hilog } from '@kit.PerformanceAnalysisKit';
@Entry @Component struct Index { @State message: string = '时辰时刻'; @State base_time: Date = new Date(Date.now()); @State str_time: string = this.formatTime(this.base_time.getHours().toString() + ":" + this.base_time.getMinutes() + ":" + this.base_time.getSeconds()); @State show_change_time: string = this.getShiChen(this.base_time.getHours(),this.base_time.getMinutes()); @State isf : boolean = true; build() {
RelativeContainer() {
Row() {
Text(this.message)
.id('shiChenShiKe')
.fontSize(50)
.fontWeight(FontWeight.Bold)
.alignRules({
center: { anchor: '__container__', align: VerticalAlign.Center },
middle: { anchor: '__container__', align: HorizontalAlign.Center }
})
}.id('row1').margin({ top: 50 }).justifyContent(FlexAlign.Center).width('100%')
Row() {
Text(this.str_time).fontSize(35).fontColor(Color.Black).fontWeight(FontWeight.Bolder)
}
.backgroundColor('#66CCDD')
.id('row2')
.margin({ top: 150 })
.justifyContent(FlexAlign.Center)
.width('100%')
Row() {
Text(this.show_change_time).fontSize(40).fontColor(Color.Black).fontWeight(FontWeight.Bolder)
}
.backgroundColor('#66CCDD')
.id('row3')
.margin({ top: 250 })
.justifyContent(FlexAlign.Center)
.width('100%')
Row() {
Button('开启时时模式').size({ width: 250, height: 80 }).fontSize(30).onClick(() => {
if(this.isf){
this.isf = false;
setInterval(()=>{this.show_change_time = this.Time_Change_Time();},1000);
}
}).id("btn1").width('100%')
}.id('row4').margin({ top: 350 }).width('100%')
}
.height('100%')
.width('100%')
}
Time_Change_Time():string{ let timeInMs = Date.now(); let dateObj = new Date(timeInMs); this.str_time = this.formatTime(dateObj.getHours() + ":" + dateObj.getMinutes() + ":" + dateObj.getSeconds()); return this.getShiChen(dateObj.getHours(), dateObj.getMinutes()); } formatTime(timeStr: string): string { let timeParts = timeStr.split(':'); let formattedParts = timeParts.map((part) => { let num = parseInt(part); return num < 10? 0${num}
: ${num}
; }); return formattedParts.join(':'); }
aboutToAppear() { hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); this.loginWithHuaweiID(); } convertToChineseTimes(hour: number): string { if (23 <= hour || hour < 1) { return "子时"; } else if (1 <= hour && hour < 3) { return "丑时"; } else if (3 <= hour && hour < 5) { return "寅时"; } else if (5 <= hour && hour < 7) { return "卯时"; } else if (7 <= hour && hour < 9) { return "辰时"; } else if (9 <= hour && hour < 11) { return "巳时"; } else if (11 <= hour && hour < 13) { return "午时"; } else if (13 <= hour && hour < 15) { return "未时"; } else if (15 <= hour && hour < 17) { return "申时"; } else if (17 <= hour && hour < 19) { return "酉时"; } else if (19 <= hour && hour < 21) { return "戌时"; } else { return "亥时"; } }
convertToChineseTime(hour: number, minute: number): string { let chineseHour = this.convertToChineseTimes(hour); let minuteMark = hour % 2 !== 0 ? "上" : "下"; if (minute < 15) { minuteMark += "一刻"; } else if (minute < 30) { minuteMark += "二刻"; } else if (minute < 45) { minuteMark += "三刻"; } else { minuteMark += "四刻"; } return ${chineseHour}${minuteMark}
; }
getShiChen(hour: number, minute: number): string { return this.convertToChineseTime(hour, minute); } /**
- Sample code for using HUAWEI ID to log in to atomic service.
- According to the Atomic Service Review Guide, when a atomic service has an account system,
- the option to log in with a HUAWEI ID must be provided.
- The following presets the atomic service to use the HUAWEI ID silent login function.
- To enable the atomic service to log in successfully using the HUAWEI ID, please refer
- to the HarmonyOS HUAWEI ID Access Guide to configure the client ID and fingerprint certificate. */ private loginWithHuaweiID() { // Create a login request and set parameters let loginRequest = new authentication.HuaweiIDProvider().createLoginWithHuaweiIDRequest(); // Whether to forcibly launch the HUAWEI ID login page when the user is not logged in with the HUAWEI ID loginRequest.forceLogin = false; // Execute login request let controller = new authentication.AuthenticationController(); controller.executeRequest(loginRequest).then((data) => { let loginWithHuaweiIDResponse = data as authentication.LoginWithHuaweiIDResponse; let authCode = loginWithHuaweiIDResponse.data?.authorizationCode; // Send authCode to the backend in exchange for unionID, session
}).catch((error: BusinessError) => {
hilog.error(0x0000, 'testTag', 'error: %{public}s', JSON.stringify(error));
if (error.code == authentication.AuthenticationErrorCode.ACCOUNT_NOT_LOGGED_IN) {
// HUAWEI ID is not logged in, it is recommended to jump to the login guide page
}
});
} } 四,新建元服务卡片 操作顺序:File>New > Service Widget > Dynamic Widget Service widget name:卡片的名称,在同一个应用/服务中,卡片名称不能重复,且只能包含大小写字母、数字和下划线。 Display name:卡片预览面板上显示的卡片名称。仅API 11 及以上Stage工程支持配置该字段。 Description:卡片的描述信息。 Language:界面开发语言,可选择创建ArkTS/JS卡片,不支持JS卡片。
Support dimension:选择卡片的规格。部分卡片支持同时设置多种规格。首次创建服务卡片时,将默认生成一个EntryCard目录,用于存放卡片快照。 Default dimension:在下拉框中可选择默认的卡片。 Ability name:选择一个挂靠服务卡片的Form Ability,或者创建一个新的Form Ability。 Module name:卡片所属的模块。