框架层:框架层为 HarmonyOS 的应用程序提供了 Java/C/C /JS 等多语言的用户程序框架和Ability 框架,以及各种软硬件服务对外开放的多语言框架 API;应用层:应用层包括系统应用和第三方非系统应用。3.系统安全 在搭载 HarmonyOS 的分布式终端上,可以保证“正确的人,通过正确的设备,正确地使用数据”。 • 通过“分布式多端协同身份认证”来保证“正确的人”。 • 通过“在分布式终端上构筑可信运行环境”来保证“正确的设备”。 • 通过“分布式数据在跨终端流动的过程中,对数据进行分类分级管理”来保证“正确地使用数据”。 开发基础知识1.应用基础知识 APP:HarmonyOS 的应用软件包以 APP Pack(Application Package)形式发布,它是由一个或多个 HAP(HarmonyOS Ability Package)以及描述每个 HAP 属性的 pack.info 组成。HAP 是Ability 的部署包,HarmonyOS 应用代码围绕 Ability 组件展开。一个 HAP 是由代码、资源、第三方库及应用配置文件组成的模块包,可分为 entry 和feature 两种模块类型。 Ability:是应用所具备的能力的抽象,一个应用可以包含一个或多个 Ability。Ability 分为两种类型:FA(Feature Ability)和 PA(Particle Ability)。FA/PA 是应用的基本组成单元,能够实现特定的业务功能。FA 有 UI 界面,而 PA 无 UI 界面。 库文件:是应用依赖的第三方代码形式,存放在 libs 目录,是.so 文件。 资源文件:应用的资源文件(字符串、图片、音频等)存放于 resources 目录下,便于开发者使用和维护。 配置文件:是应用的 Ability 信息,用于声明应用的 Ability,以及应用所需权限等信息。 pack.info:描述应用软件包中每个 HAP 的属性,由 IDE 编译生成,应用市场根据该文件进行拆包和HAP 的分类存储。 HAP 的具体属性包括: • delivery-with-install: 用于标识该 HAP 是否需要在主动安装时进行安装。 • name:HAP 文件名。 • module-type:模块类型,entry 或 feature。 • device-type:用于标识支持该 HAP 运行的设备类型。 2.应用配置文件 简介:应用的每个 HAP 的根目录下都存在一个“config.json”配置文件,主要涵盖以下三个方 面: • 应用的全局配置信息,包含应用的包名、生产厂商、版本号等基本信息。 • 应用在具体设备上的配置信息。 • HAP 包的配置信息,包含每个 Ability 必须定义的基本属性(如包名、类名、类型以及Ability 提供的能力),以及应用访问系统或其他应用受保护部分所需的权限等。 文件约定:配置文件“config.json”采用 JSON 文件格式,由属性和值两部分构成。 • 属性:属性出现顺序不分先后,且每个属性最多只允许出现一次。 • 值:每个属性的值为 JSON 的基本数据类型(数值、字符串、布尔值、数组、对象或者 null 类型)。 配置文件的内部结构:应用的配置文件“config.json”中由“app”、“deviceConfig”和“module”三个部分组成,缺一不可。配置文件的内部结构说明见下图。 app 对象的内部结构:app 对象包含应用的全局配置信息,内部结构说明见下图。 app 对象的内部结构 app 对象的内部结构 app 示例:
1. "app": {2. "bundleName": "com.huawei.hiworld.example",3. "vendor": "huawei",4. "version": {5. "code": 2,6. "name": "2.0"7. }8. "apiVersion": {9. "compatible": 3,10. "target": 311. }12. }
deviceConfig 对象的内部结构:deviceConfig 包含在具体设备上的应用配置信息,可以包含 default、car、tv、wearable、liteWearable、smartVision 等属性。default 标签内的配置是适用于所有设备通用,其他设备类型如果有特殊的需求,则需要在该设备类型的标签下进行配置。内部结构说明见下图。
default、car、tv、wearable、liteWearable、smartVision 等对象的内部结构说明,可见下图。
deviceConfig 示例:
1. "deviceConfig": {2. "default": {3. "process": "com.huawei.hiworld.example",4. "directLaunch": false,5. "supportBackup": false,6. "network": {7. "usesCleartext": true,8. "securityConfig": {9. "domainSettings": {10. "cleartextPermitted": true,11. "domains": [12. {13. "subDomains": true,14. "name": "example.ohos.com"15. }16. ]17. }18. }19. }20. }21. }
module 对象的内部结构:module 对象包含 HAP 包的配置信息,内部结构说明参见下图
module 示例:
1. "module": {2. "package": "com.example.myapplication.entry",3. "name": ".MyOHOSAbilityPackage",4. "description": "$string:description_application",5. "supportedModes": [6. "drive"7. ],8. ],9. "deviceType": [10. "car"11. ],12. "distro": {13. "deliveryWithInstall": true,14. "moduleName": "ohos_entry",15. "moduleType": "entry"16. },17. "abilities": [18. ...19. ],20. "shortcuts": [21. ...22. ],23. "js": [24. ...25. ],26. "reqPermissions": [27. ...28. ],29. "defPermissions": [30. ...31. ]32. }
distro 示例:
1. "distro": {2. "deliveryWithInstall": true,3. "moduleName": "ohos_entry",4. "moduleType": "entry"5. }
abilities 示例:
1. "abilities": [2. {3. "name": ".MainAbility",4. "description": "$string:description_main_ability",5. "icon": "$media:hiworld.png",6. "label": "HiMusic",7. "type": "page",8. "formEnabled": false,9. "launchType": "standard",10. "orientation": "unspecified",11. "permissions": [12. ],13. "visible": false,14. "skills": [15. {16. "actions": [17. "action.system.home"18. ],19. "entities": [20. "entity.system.home"21. ]22. }23. ],24. "configChanges": [25. "locale",26. "layout",27. "fontSize",28. "orientation"29. ],30. "directLaunch": false,31. "process": "string",32. "backgroundModes": [33. "dataTransfer",34. "audioPlayback",35. "audioRecording",36. "pictureInPicture",37. "voip",38. "location",39. "bluetoothInteraction",40. "wifiInteraction",41. "screenFetch"42. ],43. }44. ]
skills 示例:
1. "skills": [2. {3. "actions": [4. "action.system.home"5. ],6. "entities": [7. "entity.system.home"8. ],9. "uris": [10. {11. "scheme": "http",12. "host": "www.xxx.com",13. "port": "8080",14. "path": "query/student/name",15. "type": "text"16. }17. ]18. }19. ]
form 示例:
1. "form": {2. "formEntity": [3. "homeScreen",4. "searchbox"5. ],6. "minHeight": 100,7. "maxHeight": 200,8. "minWidth": 100,9. "maxWidth": 20010. }
js 示例:
1. "js": [2. {3. "name": "default",4. "pages": [5. "pages/index/index",6. "pages/detail/detail"7. ],8. "window": {9. "designWidth": 750,10. "autoDesignWidth": false11. }12. }13. ]
示例:
1. "shortcuts": [2. {3. "shortcutId": "id",4. "label": "$string:shortcut",5. "intents": [6. {7. "targetBundle": "com.huawei.hiworld.himusic",8. "targetClass": "com.huawei.hiworld.himusic.entry.MainAbility"9. }10. ]11. }12. ]
配置文件示例:以 JSON 文件为 config.json 的一个简单示例,该示例的应用声明为三个 Ability。
1. {2. "app": {3. "bundleName": "com.huawei.hiworld.himusic",4. "vendor": "huawei",5. "version": {6. "code": 2,7. "name": "2.0"8. }9. "apiVersion": {10. "compatible": 3,11. "target": 312. }13. },14. "deviceConfig": {15. "default": {16. }17. },18. "module": {19. "package": "com.huawei.hiworld.himusic.entry",20. "name": ".MainApplication",21. "supportedModes": [22. "drive"23. ],24. "distro": {25. "moduleType": "entry",26. "deliveryWithInstall": true,27. "moduleName": "hap-car"28. },29. "deviceType": [30. "car"31. ],32.33. "abilities": [34. {35. "name": ".MainAbility",36. "description": "himusic main ability",37. "icon": "$media:ic_launcher",38. "label": "HiMusic",39. "launchType": "standard",40. "orientation": "unspecified",41. "visible": true,42. "skills": [43. {44. "actions": [45. "action.system.home"46. ],47. "entities": [48. "entity.system.home"49. ]50. }51. ],52. "type": "page",53. "formEnabled": false54. },55. {56. "name": ".PlayService",57. "description": "himusic play ability",58. "icon": "$media:ic_launcher",59. "label": "HiMusic",60. "launchType": "standard",61. "orientation": "unspecified",62. "visible": false,63. "skills": [64. {65. "actions": [66. "action.play.music",67. "action.stop.music"68. ],69. "entities": [70. "entity.audio"71. ]72. }73. ],74. "type": "service",75. "formEnabled": false,76. "backgroundModes": [77. "audioPlayback"78. ]79. },80. {81. "name": ".UserADataAbility",82. "type": "data",83. "uri": "dataability://com.huawei.hiworld.himusic.UserADataAbility",84. "visible": true85. }86. ],87. "reqPermissions": [{88. "name": "ohos.permission.DISTRIBUTED_DATASYNC",89. "reason": "",90. "usedScene": {91. "ability": [92. "com.huawei.hiworld.himusic.entry.MainAbility",93. "com.huawei.hiworld.himusic.entry.PlayService"94. ],95. "when": "inuse"96. }97. }98. ]99. }100. }
资源文件1. resources2. |---base // 默认存在的目录3. | |---element4. | | |---string.json5. | |---media6. | | |---icon.png7. |---en_GB-vertical-car-mdpi // 限定词目录示例,需要开发者自行创建8. | |---element9. | | |---string.json10. | |---media11. | | |---icon.png12. |---rawfile // 默认存在的目录
1. {2. "boolean":[3. {4. "name":"boolean_1",5. "value":true6. },7. {8. "name":"boolean_ref",9. "value":"$boolean:boolean_1"10. }11. ]12. }
color.json 示例:
1. {2. "color":[3. {4. "name":"red",5. "value":"#ff0000"6. },7. {8. "name":"red_ref",9. "value":"$color:red"10. }11. ]12. }13. float.json 示例14. {15. "float":[16. {17. "name":"float_1",18. "value":"30.6"19. },20. {21. "name":"float_ref",22. "value":"$float:float_1"23. },24. {25. "name":"float_px",26. "value":"100px"27. }28. ]29. }30. intarray.json 示例31. {32. "intarray":[33. {34. "name":"intarray_1",35. "value":[36. 100,37. 200,38. "$integer:integer_1"39. ]40. }41. ]42. }
integer.json 示例:
1. {2. "integer":[3. {4. "name":"integer_1",5. "value":1006. },7. {8. "name":"integer_ref",9. "value":"$integer:integer_1"10. }11. ]12. }
pattern.json 示例:
1. {2. "pattern":[3. {4. "name":"base",5. "value":[6. {7. "name":"width",8. "value":"100vp"9. },10. {11. "name":"height",12. "value":"100vp"13. },14. {15. "name":"size",16. "value":"25px"17. }18. ]19. },20. {21. "name":"child",22. "parent":"base",23. "value":[24. {25. "name":"noTitile",26. "value":"Yes"27. }28. ]29. }30. ]31. }
plural.json 示例
1. {2. "plural":[3. {4. "name":"eat_apple",5. "value":[6. {7. "quantity":"one",8. "value":"%d apple"9. },10. {11. "quantity":"other",12. "value":"%d apples"13. }14. ]15. }16. ]17. }
strarray.json 示例:
1. {2. "strarray":[3. {4. "name":"size",5. "value":[6. {7. "value":"small"8. },9. {10. "value":"$string:hello"11. },12. {13. "value":"large"14. },15. {16. "value":"extra large"17. }18. ]19. }20. ]21. }
string.json 示例:
1. {2. "string":[3. {4. "name":"hello",5. "value":"hello base"6. },7. {8. "name":"app_name",9. "value":"my application"10. },11. {12. "name":"app_name_ref",13. "value":"$string:app_name"14. },15. {16. "name":"app_sys_ref",17. "value":"$ohos:string:request_location_reminder_title"18. }19. ]20. }
应用数据管理 HarmonyOS 应用数据管理支撑单设备的各种结构化数据的持久化,以及跨设备之间数据的同步、共享以及搜索功能。开发者通过应用数据管理,能够方便地完成应用程序数据在不同终端设备间的无缝衔接,满足用户跨设备使用数据的一致性体验。
本地应用数据管理:提供单设备上结构化数据的存储和访问能力。使用 SQLite 作为持久化存储引擎,提供了多种类型的本地数据库,分别是关系型数据库(Relational Database)和对象映射关系型数据库(Object Relational Mapping Database),此外还提供一种轻量级偏好数据库(Light Weight Preference Database),用以满足开发人员使用不同数据模型对应用数据进行持久化和访问的需求。
分布式数据服务:分布式数据库支持用户数据跨设备相互同步,为用户提供在多种终端设备上一致的数据访问体验。通过调用分布式数据接口,应用可以将数据保存到分布式数据库中。通过结合帐号、应用唯一标识和数据库三元组,分布式数据库对属于不同应用的数据进行隔离。
分布式文件服务:在多个终端设备间为单个设备上应用程序创建的文件提供多终端的分布式共享能力。每台设备上都存储一份全量的文件元数据,应用程序通过文件元数据中的路径,可以实现同一应用文件的跨设备访问。有关于分布式文件的详细信息,请参阅分布式文件服务。
数据搜索服务:在单个设备上,为应用程序提供搜索引擎级的全文索引管理、建立索引和搜索功能。
数据存储管理:为应用开发者提供系统存储路径、存储设备列表,存储设备属性的查询和管理功能。应用权限管理 HarmonyOS 中所有的应用均在应用沙盒内运行。默认情况下,应用只能访问有限的系统资源,系统负责管理应用对资源的访问权限。应用权限管理是由接口提供方(Ability)、接口使用方(应用)、系统(包括云侧和端侧)以及用户等多方共同参与的整个流程,保证受限接口是在约定好的规则下被正常使用,避免接口被滥用而导致用户、应用和设备受损。 权限声明 • 应用需要在 config.json 中使用“reqPermissions”属性对需要的权限逐个进行声明。 • 若使用到的三方库也涉及权限使用,也需统一在应用的 config.json 中逐个声明。 • 没有在 config.json 中声明的权限,应用就无法获得此权限的授权。 动态申请敏感权限 动态申请敏感权限基于用户可知可控的原则,需要应用在运行时主动调用系统动态申请权限的接口,系统弹框由用户授权,用户结合应用运行场景的上下文,识别出应用申请相应敏感权限的合理性,从而做出正确的选择。即使用户向应用授予了请求的权限,应用在调用受此权限管控的接口前,也应该先检查自己有无此权限,而不能把之前授予的状态持久化,因为用户在动态授予后还可以通过设置取消应用的权限。 自定义权限 HarmonyOS 为了保证应用对外提供的接口不被恶意调用,需要对调用接口的调用者进行鉴权。大多情况下,系统已定义的权限满足了应用的基本需要,若有特殊的访问控制需要,应用可在 config.json 中以"defPermissions": []属性来定义新的权限,并通过“availableScope”和“grantMode”两个属性分别确定权限的开放范围和授权方式,使得权限定义更加灵活且易于理解。有关 HarmonyOS 权限开放范围和授权方式详细的描述,请参阅权限授予方式字段说明和权限限制范围字段说明。为了避免应用自定义新权限出现重名的情况,建议应用对新权限的命名以包名的前两个字段开头,这样可以防止不同开发者的应用间出现自定义权限重名的情况。 权限保护方法 • 保护 Ability:通过在 config.json 里对应的 Ability 中配置"permissions": ["权限名"]属性,即可实现保护整个 Ability 的目的,无指定权限的应用不能访问此 Ability。 • 保护 API:若 Ability 对外提供的数据或能力有多种,且开放范围或保护级别也不同,可以针对不同的数据或能力在接口代码实现中通过 verifyPermission(String permissionName, int pid, int uid)来对 uid标识的调用者进行鉴权。 权限使用原则 • 权限申请最小化。跟用户提供的功能无关的权限,不要申请;尽量采用其他无需权限的操作来实现相应功能(如:通过 intent 拉起系统 UI 界面由用户交互、应用自己生成 uuid 代替设备 ID等)。 • 权限申请完整。应用所需权限(包括应用调用到的三方库依赖的权限)都要逐个在应用的 config.json 中按格式声明。 • 满足用户可知。应用申请的敏感权限的目的需要真实准确告知用户。 • 权限就近申请。应用在用户触发相关业务功能时,就近提示用户授予实现此功能所需的权限。 • 权限不扩散。在用户未授权的情况下,不允许提供给其他应用使用。 • 应用自定义权限防止重名。建议以包名为前缀来命名权限,防止跟系统定义的权限重名。 应用隐私保护 随着移动终端及其相关业务(如移动支付、终端云等)的普及,用户隐私保护的重要性愈发突出。应用开发者在产品设计阶段就需要考虑保护的用户隐私,提高应用的安全性。HarmonyOS 应用开发需要遵从其隐私保护规则,在应用上架应用市场时,应用市场会根据规则进行校验,如不满足条件则无法上架。 数据收集及使用公开透明 应用采集个人数据时,应清晰、明确地告知用户,并确保告知用户的个人信息将被如何使用。 • 应用申请操作系统受限权限和敏感权限时,需要明确告知用户权限申请的目的和用途,并获取用户的同意。受限权限 API 使用方案请参考权限章节。详细的 UX 设计方案请参考 UX 设计隐私方案。 图 1 敏感权限获取弹框示例 • 开发者应制定并遵从适当的隐私政策,在收集、使用留存和第三方分享用户数据时需要符合所有适用法律、政策和规定。需充分告知用户处理个人数据的种类、目的、处理方式、保留期限等,满足数据主体权利等要求。根据以上原则,我们设计了示例以供参考。隐私通知/声明的参考示例如下: 图 2 应用隐私通知示例图 图 3 应用隐私声明示例图 个人数据应当基于具体、明确、合法的目的收集,不应以与此目的不相符的方式作进一步处理。对于收集目的变更和用户撤销同意后再次使用的场景都需要用户重新同意。隐私声明变更示例图,隐私声明撤销同意示例图所示。 图 4 隐私声明变更示例图 图 5 撤销同意示例图 • 应用的隐私声明应覆盖本应用所有收集的个人数据。 • 有 UI 的 Ability 运行时需要在明显位置展示 Ability 的功能名称及开发者名称/logo。 • 应用的隐私声明应在应用首次启动时通过弹框等明显的方式展示给用户,并提供用户查看隐私声明的入口。 • 调用第三方 Ability 时,需要明确调用方与被调用方履行的隐私责任,并在声明弹框中告知数据主体相关隐私权责。 • 调用第三方 Ability 时,如涉及个人数据的分享,调用方需在隐私声明中说明分享的数据类型和数据接收者的类型。 数据收集及使用最小化 应用个人数据收集应与数据处理目的相关,且是适当、必要的。开发者应尽可能对个人数据进行匿名或化名,降低数据主体的风险。仅可收集和处理与特定目的相关且必需的个人数据,不能对数据做出与特定目的不相关的进一步处理。
敏感权限申请的时候要满足权限最小化的要求,在进行权限申请时,只申请获取必需的信息或资源所需要的权限。应用针对数据的收集要满足最小化要求,不收集与应用提供服务无关联的数据。数据使用的功能要求能够使用户受益,收集的数据不能用于与用户正常使用无关的功能。数据处理选择和控制 对个人数据处理必须要征得用户的同意,用户对其个人数据要有充分的控制权。
应用申请使用系统权限:应用弹窗提醒,向用户呈现应用需要获取的权限和权限使用目的、应用需要收集的数据和使用目的等,通过用户点击“确认”的方式完成用户授权,让用户对应用权限的授予和使用透明、可知、可控。用户可以修改、取消授予应用的权限:当用户不同意某一权限或者数据收集时,应当允许用户使用与这部分权限和数据收集不相关的功能;在进入应用的主界面之前不建议直接弹窗申请敏感权限,仅在用户使用功能时才请求对应的权限;系统对于用户的敏感数据和系统关键资源的获取设置了对应的权限,应用访问这些数据时需要申请对应的权限。数据安全 从技术上保证数据处理活动的安全性,包括个人数据的加密存储、安全传输等安全机制,系统应默认开启或采取安全保护措施。 数据存储 ①应用产生的密钥以及用户的敏感数据需要存储在应用的私有目录下,敏感数据定义可参考数据分类分级标准。 ②应用可以调用系统提供的本地数据库 RdbStore 的加密接口对敏感数据进行加密存储。接口详见关系型数据库章节。 ③应用产生的分布式数据可以调用系统的分布式数据库进行存储,对于敏感数据需要采用分布式数据库提供的加密接口进行加密,接口详见分布式数据服务章节。 安全传输 需要分别针对本地传输和远程传输采取不同的安全保护措施。 本地传输: ①应用通过 intent 跨应用传输数据时避免包含敏感数据,intent scheme url 协议使用过程中加入安全限制,防止 UXSS 等安全问题。 ②应用内组件调用应采用安全方式,避免通过隐式方式进行调用组件,防止组件劫持。 ③避免使用 socket 方式进行本地通信,如需使用,localhost 端口号随机生成,并对端口连接对象进行身份认证和鉴权。 ④本地 IPC 通信安全:作为服务提供方需要校验服务使用方的身份和访问权限,防止服务使用方进行身份仿冒或者权限绕过。 远程传输: ⑤使用 https 代替 http 进行通信,并对 https 证书进行严格校验。 ⑥ 避免进行远程端口进行通信,如需使用,需要对端口连接对象进行身份认证和鉴权。 ⑦应用进行跨设备通信时,需要校验被访问设备和应用的身份信息,防止被访问方的设备和应用进行身份仿冒。 ⑧应用进行跨设备通信时,作为服务提供方需要校验服务使用方的身份和权限,防止服务使用方进行身份仿冒或者权限绕过。 本地化处理:应用开发的数据优先在本地进行处理,对于本地无法处理的数据上传云服务要满足最小化的原则,不能默认选择上传云服务。 未成年人数据保护要求:如果应用是针对未成年人设计的,或者应用通过收集的用户年龄数据识别出用户是未成年人,开发者应该结合目标市场国家的相关法律,专门分析未成年人个人数据保护的问题。收集未成年人数据前需要征得监护人的同意。 3.快速入门 编写第一个页面 在 Java UI 框架中,提供了两种编写布局的方式:在 XML 中声明 UI 布局和在代码中创建布局。这两种方式创建出的布局没有本质差别,为了熟悉两种方式,我们将通过 XML 的方式编写第一个页面,通过代码的方式编写第二个页面。 ⑴ XML 编写页面 ①在“Project”窗口,打开“entry > src > main > resources > base”,右键点击“base”文件夹,选 择“New > Directory”,命名为“layout”。 ②右键点击“layout”文件夹,选择“New > File”,命名为“main_layout.xml”。 在“layout”文件夹下可以看到新增了“main_layout.xml”文件。 ③打开“main_layout.xml”文件,添加一个文本和一个按钮,示例代码如下:
1. <?xml version="1.0" encoding="utf-8"?>2. <DependentLayout3. xmlns:ohos="http://schemas.huawei.com/res/ohos";4. ohos:width="match_parent"5. ohos:height="match_parent"6. ohos:background_element="#000000">7. <Text8. ohos:id="$ id:text"9. ohos:width="match_content"10. ohos:height="match_content"11. ohos:center_in_parent="true"12. ohos:text="Hello World"13. ohos:text_color="white"14. ohos:text_size="32fp"/>15. <Button16. ohos:id="$ id:button"17. ohos:width="match_content"18. ohos:height="match_content"19. ohos:text_size="19fp"20. ohos:text="Next"21. ohos:top_padding="8vp"22. ohos:bottom_padding="8vp"23. ohos:right_padding="80vp"24. ohos:left_padding="80vp"25. ohos:text_color="white"26. ohos:background_element="$graphic:button_element"27. ohos:center_in_parent="true"28. ohos:align_parent_bottom="true"/>29. </DependentLayout>
④上述按钮的背景是通过“button_element”来显示的,需要在“base”目录下创建“graphic”文件夹,在“graphic”文件夹中新建一个“button_element.xml”文件。
“button_element.xml”的示例代码如下:
1. <?xml version="1.0" encoding="utf-8"?>2. <shape3. xmlns:ohos="http://schemas.huawei.com/res/ohos";4. ohos:shape="oval">5. <solid6. ohos:color="#007DFF"/>7. </shape>
⑵ 加载 XML 布局
① 在“Project”窗口中,选择“entry > src > main > java > com.example.helloworld > slice” ,打开“MainAbilitySlice.java”文件。
②重写 onStart()方法加载 XML 布局,示例代码如下:
1. package com.example.myapplication.slice;2.3. import com.example.myapplication.ResourceTable;4. import ohos.aafwk.ability.AbilitySlice;5. import ohos.aafwk.content.Intent;6.7. public class MainAbilitySlice extends AbilitySlice {8.9. @Override10. public void onStart(Intent intent) {11. super.onStart(intent);12. super.setUIContent(ResourceTable.Layout_main_layout); // 加载 XML 布局13. }14.15. @Override16. public void onActive() {17. super.onActive();18. }19.20. @Override21. public void onForeground(Intent intent) {22. super.onForeground(intent);23. }24. }
③请参考应用运行,效果如图所示:
⑶ 创建另一个页面
创建 Feature Ability
①在“Project”窗口,打开“entry > src > main > java”,右键点击“com.example.myapplication”文件夹,选择“New > Ability > Empty Feature Ability(Java)”。
②配置 Ability 时,将“Page Name”设置为“SecondAbility”,点击“Finish”。创建完成后,可以看到新增了“SecondAbility”和“SecondAbilitySlice”文件。
代码编写界面
在上面我们用 XML 的方式编写了一个包含文本和按钮的页面。为了帮助开发者熟悉在代码中创建布局的方式,接下来我们使用此方式编写第二个页面。打开 “SecondAbilitySlice.java”文件,添加一个文本,示例代码如下:
1. package com.example.myapplication.slice;2.3. import ohos.aafwk.ability.AbilitySlice;4. import ohos.aafwk.content.Intent;5. import ohos.agp.colors.RgbColor;6. import ohos.agp.components.DependentLayout;7. import ohos.agp.components.DependentLayout.LayoutConfig;8. import ohos.agp.components.Text;9. import ohos.agp.components.element.ShapeElement;10. import ohos.agp.utils.Color;11.12. import static ohos.agp.components.ComponentContainer.LayoutConfig.MATCH_PARENT;13. import static ohos.agp.components.ComponentContainer.LayoutConfig.MATCH_CONTENT;14.15. public class SecondAbilitySlice extends AbilitySlice {16.17. @Override18. public void onStart(Intent intent) {19. super.onStart(intent);20. // 声明布局21. DependentLayout myLayout = new DependentLayout(this);22. // 设置布局大小23. myLayout.setWidth(MATCH_PARENT);24. myLayout.setHeight(MATCH_PARENT);25. ShapeElement element = new ShapeElement();26. element.setRgbColor(new RgbColor(0, 0, 0));27. myLayout.setBackground(element);28.29. // 创建一个文本30. Text text = new Text(this);31. text.setText("Nice to meet you.");32. text.setWidth(MATCH_PARENT);33. text.setTextSize(55);34. text.setTextColor(Color.WHITE);35. // 设置文本的布局36. DependentLayout.LayoutConfig textConfig = new DependentLayout.LayoutConfig(MATCH_CONTENT,MATCH_CONTENT);37. textConfig.addRule(LayoutConfig.CENTER_IN_PARENT);38. text.setLayoutConfig(textConfig);39. myLayout.addComponent(text);40.41. super.setUIContent(myLayout);42. }43.44. @Override45. public void onActive() {46. super.onActive();47. }48.49. @Override50. public void onForeground(Intent intent) {51. super.onForeground(intent);52. }53. }
实现页面跳转
❶打开第一个页面的“MainAbilitySlice.java”文件,重写 onStart()方法添加按钮的响应逻辑,实现点击按钮跳转到下一页,示例代码如下:
1. package com.example.myapplication.slice;2.3. import com.example.myapplication.ResourceTable;4. import ohos.aafwk.ability.AbilitySlice;5. import ohos.aafwk.content.Intent;6. import ohos.aafwk.content.Operation;7. import ohos.agp.components.*;8.9. public class MainAbilitySlice extends AbilitySlice {10.11. @Override12. public void onStart(Intent intent) {13. super.onStart(intent);14. super.setUIContent(ResourceTable.Layout_main_layout);15. Button button = (Button) findComponentById(ResourceTable.Id_button);16.17. if (button != null) {18. // 为按钮设置点击回调19. button.setClickedListener(new Component.ClickedListener() {20. @Override21. public void onClick(Component component) {22. Intent secondIntent = new Intent();23. // 指定待启动 FA 的 bundleName 和 abilityName24. Operation operation = new Intent.OperationBuilder()25. .withDeviceId("")26. .withBundleName("com.example.myapplication")27. .withAbilityName("com.example.myapplication.SecondAbility")28. .build();29. secondIntent.setOperation(operation);30. startAbility(secondIntent); // 通过 AbilitySlice 的 startAbility 接口实现启动另一个页面31. }32. });33. }34. }35.36. @Override37. public void onActive() {38. super.onActive();39. }40.41. @Override42. public void onForeground(Intent intent) {43. super.onForeground(intent);44. }45. }
❷再次运行项目,效果如下图。
看完这些,你学废了吗?自华为鸿蒙OS发布会结束后,鸿蒙系统的热度一直稳居各大平台热榜,各大高校也开始启动了高校鸿蒙人才培养计划,清华大学、上海交大、哈工大、华中科技大学、武汉大学……为鼓励在校生参与到鸿蒙开发生态中,十几所中国顶级高校已把鸿蒙系统作为选修课。6月5号,武汉大学官方微博发布消息表明今年2月武汉大学率先开设全国高校第一个鸿蒙移动编程技术课程。计算机学院赵小刚老师和华为公司签署华为 - 教育部产学合作协同育人项目,双方开始联合设计鸿蒙应用开发课程的内容。由此可见,鸿蒙系统的课程热度
如果你真的想要学习鸿蒙系统的话,我建议大家还是去正规的培训机构或者官方授权网址学习,他们的学习计划学习目标更清晰明了。例如,初级-助理工程师HDCA两个月就可以攻下证书;中级-专业工程师掌握HarmonyOS中级开发内容就可以升级为中级鸿蒙OS工程师;HDCP高级-架构师HDCE学习每天开发网络与连接、传感器、AI开发、安全、流转等内容。不过,这些其实都不足挂齿,作为开发者我学到最后,为的是什么?——薪资,不管是初级还是高级工程师,它的预期薪资都让人心动不已,最高可达到100k!!!毕竟现在鸿蒙系统的开发者还不是很多,物以稀为贵,我只能一句wc!!!太羡慕我自己了~
花粉社群VIP加油站
猜你喜欢