diff --git a/Security/RequestUserAuthorization/.gitignore b/Security/RequestUserAuthorization/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..08d606210b3993e8f1f4535767bb3459b7b1d208 --- /dev/null +++ b/Security/RequestUserAuthorization/.gitignore @@ -0,0 +1,13 @@ +/node_modules +/oh_modules +/local.properties +/.idea +**/build +/.hvigor +.cxx +/.clangd +/.clang-format +/.clang-tidy +**/.test +/.appanalyzer +/oh-package-lock.json5 \ No newline at end of file diff --git a/Security/RequestUserAuthorization/AppScope/app.json5 b/Security/RequestUserAuthorization/AppScope/app.json5 new file mode 100644 index 0000000000000000000000000000000000000000..ac059f9d34f1cc2bd4b026c15c02f3b2cc95eb8c --- /dev/null +++ b/Security/RequestUserAuthorization/AppScope/app.json5 @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "app": { + "bundleName": "com.samples.requestuserauthorization", + "vendor": "samples", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:app_icon", + "label": "$string:app_name" + } +} diff --git a/Security/RequestUserAuthorization/AppScope/resources/base/element/string.json b/Security/RequestUserAuthorization/AppScope/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..7a5157cd1da7dacd3a5ad9306e07882ab049f582 --- /dev/null +++ b/Security/RequestUserAuthorization/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "RequestUserAuthorization" + } + ] +} diff --git a/Security/RequestUserAuthorization/AppScope/resources/base/media/app_icon.png b/Security/RequestUserAuthorization/AppScope/resources/base/media/app_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a39445dc87828b76fed6d2ec470dd455c45319e3 Binary files /dev/null and b/Security/RequestUserAuthorization/AppScope/resources/base/media/app_icon.png differ diff --git a/Security/RequestUserAuthorization/README.md b/Security/RequestUserAuthorization/README.md new file mode 100644 index 0000000000000000000000000000000000000000..3acd0701867bb5b6be95694cc30595ad705e85b9 --- /dev/null +++ b/Security/RequestUserAuthorization/README.md @@ -0,0 +1,80 @@ +# 向用户申请权限 + +### 介绍 + +本示例使用@ohos.abilityAccessCtrl,展示了应用申请权限场景。 + +### 效果预览 + +| 主页 | 授权弹窗 | 二次授权弹窗 | 二次授权页面 | +| ------------------------------------ | ---------------------------------------- | ---------------------------------------------------- | :----------------------------------------------------- | +| ![main](screenshots/main.png) | ![dialog](screenshots/dialog.png) | ![seconddialog](screenshots/seconddialog.png) | ![secondability](screenshots/secondability.png) | + +使用说明 + +1. 打开应用,点击**检测权限**按钮,出现提示信息“权限未申请”。 + +2. 点击**在Page中申请权限**按钮,跳到Page页面,出现授权弹窗,点击**取消**按钮,返回主页点击**检测权限**按钮,出现提示信息“权限未申请”。 + +3. 点击**在UIAbility中申请权限**按钮,跳到**secondAbility**页面,出现授权弹窗,点击**取消**按钮,出现二次授权弹窗,选择**仅使用期间允许**选项,点击**导航到EntryAbility**按钮返回主页,点击**检测权限**按钮,出现提示信息“未申请精确定位权限”。 + +4. 再次点击**在UIAbility中申请权限** 按钮,跳到**secondAbility**页面,出现授权弹窗,点击**仅使用期间允许**按钮,点击**导航到EntryAbility**按钮返回主页,点击**检测权限**按钮,出现提示信息“权限已申请“。 + +### 工程目录 +``` +RequsetUserAuthorization +├──entry/src/main +│ ├──ets // ets代码区 +│ │ ├──entryability +│ │ │ └──EntryAbility.ets // 程序入口类 +| | ├──pages // 页面文件 +│ │ │ └──Index.ets // RequsetUserAuthorization主页 +│ │ ├──reqpermissioninui +│ │ │ └──pages +│ │ │ └──Index.ets // UI申请权限页面 +│ │ ├──secondability +│ │ │ └──SecondAbility.ets // SecondAbility入口 +| | ├──secondpages // SecondAbility页面文件 +│ │ │ └──Index.ets // 二次申请权限页面 +│ │ └──utils // 工具文件 +│ │ └──PermissionUtil.ets // 校验权限工具 +| ├──resources // 资源文件目录 +│ │ +``` +### 具体实现 + +* 本示例分为权限检测模块、向用户申请权限模块 + * 权限检测模块 + * 使用bundleManager接口中getBundleInfoForSelf方法获取应用程序的accessTokenID,根据accessTokenID使用abilityAccessCtrl接口中checkAccessToken方法检测权限是否被申请。 + * 接口参考:[@ohos.abilityAccessCtrl](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-ability-kit/js-apis-abilityAccessCtrl.md),[@ohos.bundle.bundleManager](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-ability-kit/js-apis-bundleManager.md) + * 向用户申请权限模块 + * 使用abilityAccessCtrl接口中requestPermissionsFromUser方法向用户申请权限,用户拒绝后使用requestPermissionOnSetting方法拉起二次授权功能。 + * 接口参考:[@ohos.abilityAccessCtrl](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-ability-kit/js-apis-abilityAccessCtrl.md) + +### 相关权限 + +1. 允许应用获取设备位置信息权限:[ohos.permission.LOCATION](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/security/AccessToken/permissions-for-all-user.md#ohospermissionlocation) + +2. 允许应用获取设备模糊位置信息:[ohos.permission.APPROXIMATELY_LOCATION](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/security/AccessToken/permissions-for-all-user.md#ohospermissionapproximately_location) + +### 依赖 + +不涉及。 + +### 约束与限制 + +1. 本示例仅支持标准系统上运行,支持设备:华为手机。 +2. HarmonyOS系统:HarmonyOS 5.1.1 Release及以上。 +3. DevEco Studio版本:DevEco Studio 5.1.1 Release及以上。 +4. HarmonyOS SDK版本:HarmonyOS 5.1.1 Release及以上。 + +### 下载 + +如需单独下载本工程,执行如下命令: +``` +git init +git config core.sparsecheckout true +echo Security/RequsetUserAuthorization/ > .git/info/sparse-checkout +git remote add origin https://gitee.com/harmonyos_samples/guide-snippets.git +git pull origin master +``` \ No newline at end of file diff --git a/Security/RequestUserAuthorization/build-profile.json5 b/Security/RequestUserAuthorization/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..3827fb172b316e1e0076c8c76f843921c6c88117 --- /dev/null +++ b/Security/RequestUserAuthorization/build-profile.json5 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "app": { + "signingConfigs": [ + ], + "products": [ + { + "name": "default", + "signingConfig": "default", + "compatibleSdkVersion": "5.1.1(19)", + "targetSdkVersion":"5.1.1(19)", + "runtimeOS": "HarmonyOS", + "buildOption": { + "strictMode": { + "caseSensitiveCheck": true, + "useNormalizedOHMUrl": true + } + } + } + ], + "buildModeSet": [ + { + "name": "debug", + }, + { + "name": "release" + } + ] + }, + "modules": [ + { + "name": "entry", + "srcPath": "./entry", + "targets": [ + { + "name": "default", + "applyToProducts": [ + "default" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/Security/RequestUserAuthorization/code-linter.json5 b/Security/RequestUserAuthorization/code-linter.json5 new file mode 100644 index 0000000000000000000000000000000000000000..28586467ee7a761c737d8654a73aed6fddbc3c71 --- /dev/null +++ b/Security/RequestUserAuthorization/code-linter.json5 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "files": [ + "**/*.ets" + ], + "ignore": [ + "**/src/ohosTest/**/*", + "**/src/test/**/*", + "**/src/mock/**/*", + "**/node_modules/**/*", + "**/oh_modules/**/*", + "**/build/**/*", + "**/.preview/**/*" + ], + "ruleSet": [ + "plugin:@performance/recommended", + "plugin:@typescript-eslint/recommended" + ], + "rules": { + } +} \ No newline at end of file diff --git a/Security/RequestUserAuthorization/entry/.gitignore b/Security/RequestUserAuthorization/entry/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..eadab4e1522296628f32a70228b2c758ecab4759 --- /dev/null +++ b/Security/RequestUserAuthorization/entry/.gitignore @@ -0,0 +1,7 @@ +/node_modules +/oh_modules +/.preview +/build +/.cxx +/.test +/oh-package-lock.json5 \ No newline at end of file diff --git a/Security/RequestUserAuthorization/entry/build-profile.json5 b/Security/RequestUserAuthorization/entry/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..e7569e3056e27af38e9991b7ea73ec10f3ba8a05 --- /dev/null +++ b/Security/RequestUserAuthorization/entry/build-profile.json5 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "apiType": "stageMode", + "buildOption": { + }, + "buildOptionSet": [ + { + "name": "release", + "arkOptions": { + "obfuscation": { + "ruleOptions": { + "enable": false, + "files": [ + "./obfuscation-rules.txt" + ] + } + } + } + }, + ], + "targets": [ + { + "name": "default" + }, + { + "name": "ohosTest", + } + ] +} \ No newline at end of file diff --git a/Security/RequestUserAuthorization/entry/hvigorfile.ts b/Security/RequestUserAuthorization/entry/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..a3d28cb60475cede46d0aa36973096d5544dbcd1 --- /dev/null +++ b/Security/RequestUserAuthorization/entry/hvigorfile.ts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { hapTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + plugins: [] /* Custom plugin to extend the functionality of Hvigor. */ +} diff --git a/Security/RequestUserAuthorization/entry/obfuscation-rules.txt b/Security/RequestUserAuthorization/entry/obfuscation-rules.txt new file mode 100644 index 0000000000000000000000000000000000000000..272efb6ca3f240859091bbbfc7c5802d52793b0b --- /dev/null +++ b/Security/RequestUserAuthorization/entry/obfuscation-rules.txt @@ -0,0 +1,23 @@ +# Define project specific obfuscation rules here. +# You can include the obfuscation configuration files in the current module's build-profile.json5. +# +# For more details, see +# https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/source-obfuscation-V5 + +# Obfuscation options: +# -disable-obfuscation: disable all obfuscations +# -enable-property-obfuscation: obfuscate the property names +# -enable-toplevel-obfuscation: obfuscate the names in the global scope +# -compact: remove unnecessary blank spaces and all line feeds +# -remove-log: remove all console.* statements +# -print-namecache: print the name cache that contains the mapping from the old names to new names +# -apply-namecache: reuse the given cache file + +# Keep options: +# -keep-property-name: specifies property names that you want to keep +# -keep-global-name: specifies names that you want to keep in the global scope + +-enable-property-obfuscation +-enable-toplevel-obfuscation +-enable-filename-obfuscation +-enable-export-obfuscation \ No newline at end of file diff --git a/Security/RequestUserAuthorization/entry/oh-package.json5 b/Security/RequestUserAuthorization/entry/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..c9cb6c8174858277c9b0d465a51547dcab16d5ff --- /dev/null +++ b/Security/RequestUserAuthorization/entry/oh-package.json5 @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "name": "entry", + "version": "1.0.0", + "description": "Please describe the basic information.", + "main": "", + "author": "", + "license": "", + "dependencies": {} +} + diff --git a/Security/RequestUserAuthorization/entry/src/main/ets/entryability/EntryAbility.ets b/Security/RequestUserAuthorization/entry/src/main/ets/entryability/EntryAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..6414ace7d908f49792a1f028d57b6af68e398604 --- /dev/null +++ b/Security/RequestUserAuthorization/entry/src/main/ets/entryability/EntryAbility.ets @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit'; +import { window } from '@kit.ArkUI'; + + +export default class EntryAbility extends UIAbility { + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); + } + + onDestroy(): void { + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy'); + } + + onWindowStageCreate(windowStage: window.WindowStage): void { + // Main window is created, set main page for this ability + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); + + windowStage.loadContent('pages/Index', (err) => { + if (err.code) { + hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); + return; + } + hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.'); + }); + } + + onWindowStageDestroy(): void { + // Main window is destroyed, release UI related resources + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy'); + } + + onForeground(): void { + // Ability has brought to foreground + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground'); + } + + onBackground(): void { + // Ability has back to background + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground'); + } +} diff --git a/Security/RequestUserAuthorization/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets b/Security/RequestUserAuthorization/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..b1e212947256c5533c7b06285a597c94f840a6e3 --- /dev/null +++ b/Security/RequestUserAuthorization/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { BackupExtensionAbility, BundleVersion } from '@kit.CoreFileKit'; + +export default class EntryBackupAbility extends BackupExtensionAbility { + async onBackup() { + hilog.info(0x0000, 'testTag', 'onBackup ok'); + } + + async onRestore(bundleVersion: BundleVersion) { + hilog.info(0x0000, 'testTag', 'onRestore ok %{public}s', JSON.stringify(bundleVersion)); + } +} \ No newline at end of file diff --git a/Security/RequestUserAuthorization/entry/src/main/ets/pages/Index.ets b/Security/RequestUserAuthorization/entry/src/main/ets/pages/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..00dd1a5f560bdd38907f6d098a72d753387b17c7 --- /dev/null +++ b/Security/RequestUserAuthorization/entry/src/main/ets/pages/Index.ets @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { common, Want } from '@kit.AbilityKit'; +import { checkPermissions } from '../utils/PermissionUtil'; +import router from '@ohos.router'; +import { hilog } from '@kit.PerformanceAnalysisKit'; + +@Entry +@Component +struct Index { + toSecondAbilityIndex() { + let context = getContext(this) as common.UIAbilityContext; + let want: Want = { + 'deviceId': '', + 'bundleName': 'com.samples.requestuserauthorization', + 'abilityName': 'SecondAbility', + 'moduleName': 'entry', + }; + context.startAbility(want).then(() => { + console.info(`start second ability index page succeed with ${JSON.stringify(want)}`); + }).catch((error: Error) => { + console.error(`start second ability index page failedwith ${error}`); + }); + } + + build() { + Column() { + Button($r('app.string.req_permission_page')) + .onClick(() => { + router.pushUrl({ url: 'reqpermissioninui/pages/Index' }); + }) + Button($r('app.string.req_permission_ability')) + .onClick(() => { + this.toSecondAbilityIndex(); + }) + Button($r('app.string.check_permission')) + .onClick(() => { + checkPermissions(); + }) + .type(ButtonType.Circle) + .backgroundColor(Color.Gray) + .height(100) + .width(100) + } + .width('100%') + .height('100%') + .justifyContent(FlexAlign.SpaceEvenly) + } +} \ No newline at end of file diff --git a/Security/RequestUserAuthorization/entry/src/main/ets/reqpermissioninui/pages/Index.ets b/Security/RequestUserAuthorization/entry/src/main/ets/reqpermissioninui/pages/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..68462256205cc6c3035cac0ce3d3233dba202cee --- /dev/null +++ b/Security/RequestUserAuthorization/entry/src/main/ets/reqpermissioninui/pages/Index.ets @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { router } from '@kit.ArkUI'; +// [Start request_permission_in_UI] +import { abilityAccessCtrl, common, Permissions } from '@kit.AbilityKit'; +import { BusinessError } from '@kit.BasicServicesKit'; + +const permissions: Permissions[] = ['ohos.permission.LOCATION', 'ohos.permission.APPROXIMATELY_LOCATION']; + +function reqPermissionsFromUser(permissions: Array, context: common.UIAbilityContext): void { + let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager(); + // requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗 + atManager.requestPermissionsFromUser(context, permissions).then((data) => { + let grantStatus: number[] = data.authResults; + let length: number = grantStatus.length; + for (let i = 0; i < length; i++) { + if (grantStatus[i] === 0) { + // 用户授权,可以继续访问目标操作 + } else { + // 用户拒绝授权,提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限 + return; + } + } + // 授权成功 + }).catch((err: BusinessError) => { + console.error(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`); + }) +} + +@Entry +@Component +struct Index { + aboutToAppear() { + const context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; + reqPermissionsFromUser(permissions, context); + } + + build() { + // [StartExclude request_permission_in_UI] + Column() { + Button($r('app.string.return_main')) + .onClick(() => { + router.back(); + }) + } + .width('100%') + .height('100%') + .justifyContent(FlexAlign.SpaceEvenly) + // [EndExclude request_permission_in_UI] + } +} +// [End request_permission_in_UI] \ No newline at end of file diff --git a/Security/RequestUserAuthorization/entry/src/main/ets/secondability/SecondAbility.ets b/Security/RequestUserAuthorization/entry/src/main/ets/secondability/SecondAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..bb2269f32f7b00cd587beb9a979df8c3d9b70ed3 --- /dev/null +++ b/Security/RequestUserAuthorization/entry/src/main/ets/secondability/SecondAbility.ets @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { hilog } from '@kit.PerformanceAnalysisKit'; +// [Start request_permission_in_UIAbility] +import { abilityAccessCtrl, AbilityConstant, common, Permissions, UIAbility, Want } from '@kit.AbilityKit'; +import { window } from '@kit.ArkUI'; +import { BusinessError } from '@kit.BasicServicesKit'; + +const permissions: Permissions[] = ['ohos.permission.LOCATION', 'ohos.permission.APPROXIMATELY_LOCATION']; + +function reqPermissionsFromUser(permissions: Array, context: common.UIAbilityContext): void { + // [Start second_request_permission] + let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager(); + // [StartExclude second_request_permission] + // requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗 + atManager.requestPermissionsFromUser(context, permissions).then((data) => { + let grantStatus: number[]= data.authResults; + let length: number = grantStatus.length; + for (let i = 0; i < length; i++) { + if (grantStatus[i] === 0) { + // 用户授权,可以继续访问目标操作 + + } else { + // 用户拒绝授权,拉起二次授权功能 + + // [EndExclude second_request_permission] + atManager.requestPermissionOnSetting(context, ['ohos.permission.APPROXIMATELY_LOCATION']) + .then((data: Array) => { + console.info('data:' + JSON.stringify(data)); + }) + .catch((err: BusinessError) => { + console.error('data:' + JSON.stringify(err)); + }); + // [End second_request_permission] + return; + } + } + // 授权成功 + }).catch((err: BusinessError) => { + console.error(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`); + }) +} + +export default class SecondAbility extends UIAbility { + // [StartExclude request_permission_in_UIAbility] + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); + } + + onDestroy(): void { + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy'); + } + // [EndExclude request_permission_in_UIAbility] + onWindowStageCreate(windowStage: window.WindowStage): void { + // [StartExclude request_permission_in_UIAbility] + // Main window is created, set main page for this ability + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); + // [EndExclude request_permission_in_UIAbility] + windowStage.loadContent('secondpages/Index', (err) => { + reqPermissionsFromUser(permissions, this.context); + // [StartExclude request_permission_in_UIAbility] + if (err.code) { + hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); + return; + } + hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.'); + // [EndExclude request_permission_in_UIAbility] + }); + } + // [StartExclude request_permission_in_UIAbility] + onWindowStageDestroy(): void { + // Main window is destroyed, release UI related resources + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy'); + } + + onForeground(): void { + // Ability has brought to foreground + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground'); + } + + onBackground(): void { + try { + this.context.terminateSelf((err: BusinessError) => { + if (err.code) { + // 处理业务逻辑错误 + hilog.error(0x0000, 'testTag', '%{public}s', + `terminateSelf failed, code is ${err.code}, message is ${err.message}`); + return; + } + // 执行正常业务 + hilog.info(0x0000, 'testTag', '%{public}s', 'terminateSelf succeed'); + }); + } catch (err) { + // 捕获同步的参数错误 + let code = (err as BusinessError).code; + let message = (err as BusinessError).message; + hilog.error(0x0000, 'testTag', '%{public}s', `terminateSelf failed, code is ${code}, message is ${message}`); + } + // Ability has back to background + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground'); + + } + // [EndExclude request_permission_in_UIAbility] +} +// [End request_permission_in_UIAbility] diff --git a/Security/RequestUserAuthorization/entry/src/main/ets/secondpages/Index.ets b/Security/RequestUserAuthorization/entry/src/main/ets/secondpages/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..ed3414aacfba74567058d21a9f74692cbe492817 --- /dev/null +++ b/Security/RequestUserAuthorization/entry/src/main/ets/secondpages/Index.ets @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { common, Want } from '@kit.AbilityKit'; +import { hilog } from '@kit.PerformanceAnalysisKit'; + +@Entry +@Component +struct Index { + build() { + Column() { + Button($r('app.string.return_entryability')) + .onClick(() => { + let context = getContext(this) as common.UIAbilityContext; + let want: Want = { + 'deviceId': '', + 'bundleName': 'com.samples.requestuserauthorization', + 'abilityName': 'EntryAbility', + 'moduleName': 'entry', + }; + context.startAbility(want).then(() => { + console.info(`start entry ability index page succeed with ${JSON.stringify(want)}`); + }).catch((error: Error) => { + console.error(`start entry ability index page failedwith ${error}`); + }); + }) + } + .width('100%') + .height('100%') + .justifyContent(FlexAlign.SpaceEvenly) + } +} \ No newline at end of file diff --git a/Security/RequestUserAuthorization/entry/src/main/ets/utils/PermissionUtil.ets b/Security/RequestUserAuthorization/entry/src/main/ets/utils/PermissionUtil.ets new file mode 100644 index 0000000000000000000000000000000000000000..fba1c71362d596d0e68d131d4da399b1a3c392ee --- /dev/null +++ b/Security/RequestUserAuthorization/entry/src/main/ets/utils/PermissionUtil.ets @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { promptAction } from '@kit.ArkUI'; +// [Start check_permission_func] +import { abilityAccessCtrl, bundleManager, Permissions } from '@kit.AbilityKit'; +import { BusinessError } from '@kit.BasicServicesKit'; + +async function checkPermissionGrant(permission: Permissions): Promise { + let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager(); + let grantStatus: abilityAccessCtrl.GrantStatus = abilityAccessCtrl.GrantStatus.PERMISSION_DENIED; + // 获取应用程序的accessTokenID + let tokenId: number = 0; + try { + let bundleInfo: bundleManager.BundleInfo = + await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION); + let appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo; + tokenId = appInfo.accessTokenId; + } catch (error) { + const err: BusinessError = error as BusinessError; + console.error(`Failed to get bundle info for self. Code is ${err.code}, message is ${err.message}`); + } + // 校验应用是否被授予权限 + try { + grantStatus = await atManager.checkAccessToken(tokenId, permission); + } catch (error) { + const err: BusinessError = error as BusinessError; + console.error(`Failed to check access token. Code is ${err.code}, message is ${err.message}`); + } + return grantStatus; +} + +async function checkPermissions(): Promise { + let grantStatus1: boolean = await checkPermissionGrant('ohos.permission.LOCATION') === + abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED; // 获取精确定位权限状态 + let grantStatus2: boolean = await checkPermissionGrant('ohos.permission.APPROXIMATELY_LOCATION') === + abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED; // 获取模糊定位权限状态 + // 精确定位权限只能跟模糊定位权限一起申请,或者已经有模糊定位权限才能申请精确定位权限 + if (grantStatus2 && !grantStatus1) { + // 申请精确定位权限 + // [StartExclude check_permission_func] + promptAction.showToast({ message: $r('app.string.location_not_apply') }); + // [EndExclude check_permission_func] + } else if (!grantStatus1 && !grantStatus2) { + // 申请模糊定位权限与精确定位权限或单独申请模糊定位权限 + // [StartExclude check_permission_func] + promptAction.showToast({ message: $r('app.string.permission_not_apply') }); + // [EndExclude check_permission_func] + } else { + // 已经授权,可以继续访问目标操作 + // [StartExclude check_permission_func] + promptAction.showToast({ message: $r('app.string.permission_apply') }); + // [EndExclude check_permission_func] + } +} +// [End check_permission_func] +export { + checkPermissionGrant, checkPermissions +} \ No newline at end of file diff --git a/Security/RequestUserAuthorization/entry/src/main/module.json5 b/Security/RequestUserAuthorization/entry/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..a00e217cb08e7b00014c79de361bb4d227245285 --- /dev/null +++ b/Security/RequestUserAuthorization/entry/src/main/module.json5 @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "module": { + "name": "entry", + "type": "entry", + "description": "$string:module_desc", + "mainElement": "EntryAbility", + "deviceTypes": [ + "default", + "tablet" + ], + "deliveryWithInstall": true, + "installationFree": false, + "pages": "$profile:main_pages", + "abilities": [ + { + "name": "EntryAbility", + "srcEntry": "./ets/entryability/EntryAbility.ets", + "description": "$string:EntryAbility_desc", + "icon": "$media:layered_image", + "label": "$string:EntryAbility_label", + "startWindowIcon": "$media:startIcon", + "startWindowBackground": "$color:start_window_background", + "exported": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ] + }, + { + "name": "SecondAbility", + "srcEntry": "./ets/secondability/SecondAbility.ets", + "description": "$string:SecondAbility_desc", + "icon": "$media:layered_image", + "label": "$string:SecondAbility_label", + "startWindowIcon": "$media:startIcon", + "startWindowBackground": "$color:start_window_background" + } + ], + "extensionAbilities": [ + { + "name": "EntryBackupAbility", + "srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets", + "type": "backup", + "exported": false, + "metadata": [ + { + "name": "ohos.extension.backup", + "resource": "$profile:backup_config" + } + ] + } + ], + "requestPermissions": [ + { + "name": "ohos.permission.APPROXIMATELY_LOCATION", + "reason": "$string:approximately_location_permission_reason", + "usedScene": { + "abilities": [ + "FormAbility" + ], + "when": "inuse" + } + }, + { + "name": "ohos.permission.LOCATION", + "reason": "$string:location_permission_reason", + "usedScene": { + "abilities": [ + "FormAbility" + ], + "when": "inuse" + }, + } + ] + } +} \ No newline at end of file diff --git a/Security/RequestUserAuthorization/entry/src/main/resources/base/element/color.json b/Security/RequestUserAuthorization/entry/src/main/resources/base/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..3c712962da3c2751c2b9ddb53559afcbd2b54a02 --- /dev/null +++ b/Security/RequestUserAuthorization/entry/src/main/resources/base/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#FFFFFF" + } + ] +} \ No newline at end of file diff --git a/Security/RequestUserAuthorization/entry/src/main/resources/base/element/string.json b/Security/RequestUserAuthorization/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..62ea225af1ad051291786d4f7d42accf2600f87c --- /dev/null +++ b/Security/RequestUserAuthorization/entry/src/main/resources/base/element/string.json @@ -0,0 +1,64 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "用户权限请求" + }, + { + "name": "approximately_location_permission_reason", + "value": "用于模糊定位" + }, + { + "name": "location_permission_reason", + "value": "用于获取定位" + }, + { + "name": "SecondAbility_desc", + "value": "description" + }, + { + "name": "SecondAbility_label", + "value": "label" + }, + { + "name": "check_permission", + "value": "检测权限" + }, + { + "name": "req_permission_ability", + "value": "在UIAbility中申请权限" + }, + { + "name": "req_permission_page", + "value": "在Page中申请权限" + }, + { + "name": "return_entryability", + "value": "导航到EntryAbility" + }, + { + "name": "return_main", + "value": "返回主页" + }, + { + "name": "location_not_apply", + "value": "未申请精确定位权限" + }, + { + "name": "permission_not_apply", + "value": "权限未申请" + }, + { + "name": "permission_apply", + "value": "返回主页" + } + ] +} \ No newline at end of file diff --git a/Security/RequestUserAuthorization/entry/src/main/resources/base/media/background.png b/Security/RequestUserAuthorization/entry/src/main/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..f939c9fa8cc8914832e602198745f592a0dfa34d Binary files /dev/null and b/Security/RequestUserAuthorization/entry/src/main/resources/base/media/background.png differ diff --git a/Security/RequestUserAuthorization/entry/src/main/resources/base/media/foreground.png b/Security/RequestUserAuthorization/entry/src/main/resources/base/media/foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..4483ddad1f079e1089d685bd204ee1cfe1d01902 Binary files /dev/null and b/Security/RequestUserAuthorization/entry/src/main/resources/base/media/foreground.png differ diff --git a/Security/RequestUserAuthorization/entry/src/main/resources/base/media/layered_image.json b/Security/RequestUserAuthorization/entry/src/main/resources/base/media/layered_image.json new file mode 100644 index 0000000000000000000000000000000000000000..fb49920440fb4d246c82f9ada275e26123a2136a --- /dev/null +++ b/Security/RequestUserAuthorization/entry/src/main/resources/base/media/layered_image.json @@ -0,0 +1,7 @@ +{ + "layered-image": + { + "background" : "$media:background", + "foreground" : "$media:foreground" + } +} \ No newline at end of file diff --git a/Security/RequestUserAuthorization/entry/src/main/resources/base/media/startIcon.png b/Security/RequestUserAuthorization/entry/src/main/resources/base/media/startIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..205ad8b5a8a42e8762fbe4899b8e5e31ce822b8b Binary files /dev/null and b/Security/RequestUserAuthorization/entry/src/main/resources/base/media/startIcon.png differ diff --git a/Security/RequestUserAuthorization/entry/src/main/resources/base/profile/backup_config.json b/Security/RequestUserAuthorization/entry/src/main/resources/base/profile/backup_config.json new file mode 100644 index 0000000000000000000000000000000000000000..78f40ae7c494d71e2482278f359ec790ca73471a --- /dev/null +++ b/Security/RequestUserAuthorization/entry/src/main/resources/base/profile/backup_config.json @@ -0,0 +1,3 @@ +{ + "allowToBackupRestore": true +} \ No newline at end of file diff --git a/Security/RequestUserAuthorization/entry/src/main/resources/base/profile/main_pages.json b/Security/RequestUserAuthorization/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..09fcbc83ac3a8443883f2b2633559260379142a1 --- /dev/null +++ b/Security/RequestUserAuthorization/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,7 @@ +{ + "src": [ + "pages/Index", + "reqpermissioninui/pages/Index", + "secondpages/Index" + ] +} diff --git a/Security/RequestUserAuthorization/entry/src/main/resources/en_US/element/string.json b/Security/RequestUserAuthorization/entry/src/main/resources/en_US/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..9e0626770a741071470d898b2ede59fd09d89f5d --- /dev/null +++ b/Security/RequestUserAuthorization/entry/src/main/resources/en_US/element/string.json @@ -0,0 +1,24 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "requestUserAuthorization" + }, + { + "name": "SecondAbility_desc", + "value": "description" + }, + { + "name": "SecondAbility_label", + "value": "secondAbility" + } + ] +} \ No newline at end of file diff --git a/Security/RequestUserAuthorization/entry/src/main/resources/zh_CN/element/string.json b/Security/RequestUserAuthorization/entry/src/main/resources/zh_CN/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..3e22296527cba995052f4b8aba2586b1144aeb57 --- /dev/null +++ b/Security/RequestUserAuthorization/entry/src/main/resources/zh_CN/element/string.json @@ -0,0 +1,24 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "模块描述" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "用户权限请求" + }, + { + "name": "SecondAbility_desc", + "value": "description" + }, + { + "name": "SecondAbility_label", + "value": "二次授权应用" + } + ] +} \ No newline at end of file diff --git a/Security/RequestUserAuthorization/entry/src/mock/mock-config.json5 b/Security/RequestUserAuthorization/entry/src/mock/mock-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..b9a78e201535765168a92d3543c690273ecdc019 --- /dev/null +++ b/Security/RequestUserAuthorization/entry/src/mock/mock-config.json5 @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ +} \ No newline at end of file diff --git a/Security/RequestUserAuthorization/entry/src/ohosTest/ets/test/Ability.test.ets b/Security/RequestUserAuthorization/entry/src/ohosTest/ets/test/Ability.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..dd71165a0139416af26f6b679c9bf61e407bdf6d --- /dev/null +++ b/Security/RequestUserAuthorization/entry/src/ohosTest/ets/test/Ability.test.ets @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry'; +import { describe, it, expect } from '@ohos/hypium'; +import { Driver, ON } from '@kit.TestKit'; +import Logger from '../utils/Logger'; + +const BUNDLE = 'RequestUserAuthorization_'; +const DELAY_TIME = 1000; +let abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator(); +let manage = abilityDelegator.getAppContext().resourceManager; + +async function getResourceString(resource: Resource): Promise { + let text = await manage.getStringValue(resource); + return text; +} + +export default function abilityTest() { + let driver = Driver.create(); + describe('RequestUserAuthorizationTest', () => { + /** + * 拉起应用 + */ + it(BUNDLE + 'StartAbility_001', 0, async (done: Function) => { + Logger.info(BUNDLE + 'StartAbility_001 begin'); + try { + await abilityDelegator.startAbility({ + bundleName: 'com.samples.requestuserauthorization', + abilityName: 'EntryAbility' + }) + done(); + } catch (err) { + Logger.info(BUNDLE + 'StartAbility_001,err.code:' + err.code); + expect(0).assertEqual(err.code) + done(); + } + Logger.info(BUNDLE + 'StartAbility_001 end'); + }) + /** + * 检测当前应用权限 + */ + it(BUNDLE + 'CheckPermissionFunction_001', 0, async (done: Function) => { + Logger.info(BUNDLE + 'CheckPermissionFunction_001 begin'); + await driver.delayMs(DELAY_TIME); + // 点击检测权限 + let str = await getResourceString($r('app.string.check_permission')); + await driver.assertComponentExist(ON.text(str)); + let checkBtn = await driver.findComponent(ON.text(str)); + await checkBtn.click(); + await driver.delayMs(DELAY_TIME); + Logger.info(BUNDLE + 'CheckPermissionFunction_001 end'); + done(); + }) + /** + * 在Page中申请权限并取消 + */ + it(BUNDLE + 'CancelPermissionInPageFunction_001', 0, async (done: Function) => { + Logger.info(BUNDLE + 'CancelPermissionInPageFunction_001 begin'); + await driver.delayMs(DELAY_TIME); + // 点击在Page中申请权限 + let str = await getResourceString($r('app.string.req_permission_page')); + await driver.assertComponentExist(ON.text(str)); + let reqPermissionInUI = await driver.findComponent(ON.text(str)); + await reqPermissionInUI.click(); + await driver.delayMs(DELAY_TIME); + // 点击取消授权 + str = await getResourceString($r('app.string.cancel')); + await driver.assertComponentExist(ON.text(str)); + let cancelBtn = await driver.findComponent(ON.text(str)); + await cancelBtn.click(); + await driver.delayMs(DELAY_TIME); + // 返回主页 + str = await getResourceString($r('app.string.return_main')); + await driver.assertComponentExist(ON.text(str)); + let backBtn = await driver.findComponent(ON.text(str)); + await backBtn.click(); + await driver.delayMs(DELAY_TIME); + // 点击检测权限 + str = await getResourceString($r('app.string.check_permission')); + await driver.assertComponentExist(ON.text(str)); + let checkPermissionBtn = await driver.findComponent(ON.text(str)); + await checkPermissionBtn.click(); + await driver.delayMs(DELAY_TIME); + Logger.info(BUNDLE + 'CancelPermissionInPageFunction_001 end'); + done(); + }) + /** + * 在UIAbility中取消申请权限并拉起二次授权 + */ + it(BUNDLE + 'CancelPermissionInUIAbilityFunction_001', 0, async (done: Function) => { + Logger.info(BUNDLE + 'CancelPermissionInUIAbilityFunction_001 begin'); + await driver.delayMs(DELAY_TIME); + // 点击在UIAbility中申请权限 + let str = await getResourceString($r('app.string.req_permission_ability')); + await driver.assertComponentExist(ON.text(str)); + let reqPermissionInAbility = await driver.findComponent(ON.text(str)); + await reqPermissionInAbility.click(); + await driver.delayMs(DELAY_TIME); + // 点击取消 + str = await getResourceString($r('app.string.cancel')); + await driver.assertComponentExist(ON.text(str)); + let cancelBtn = await driver.findComponent(ON.text(str)); + await cancelBtn.click(); + await driver.delayMs(DELAY_TIME); + // 点击仅使用期间允许 + str = await getResourceString($r('app.string.allowed_only_during_use')); + await driver.assertComponentExist(ON.text(str)); + let agreeBtn = await driver.findComponent(ON.text(str)); + await agreeBtn.click(); + await driver.delayMs(DELAY_TIME); + // 点击导航到EntryAbility + str = await getResourceString($r('app.string.return_entryability')); + await driver.assertComponentExist(ON.text(str)); + let backBtn = await driver.findComponent(ON.text(str)); + await backBtn.click(); + await driver.delayMs(DELAY_TIME); + // 点击检测权限 + str = await getResourceString($r('app.string.check_permission')); + await driver.assertComponentExist(ON.text(str)); + let checkPermissionBtn = await driver.findComponent(ON.text(str)); + await checkPermissionBtn.click(); + await driver.delayMs(DELAY_TIME); + Logger.info(BUNDLE + 'CancelPermissionInUIAbilityFunction_001 end'); + done(); + }) + + /** + * 在UIAbility中同意授权 + */ + it(BUNDLE + 'AllowPermissionInUIAbilityFunction_001', 0, async (done: Function) => { + Logger.info(BUNDLE + 'AllowPermissionInUIAbilityFunction_001 begin'); + await driver.delayMs(DELAY_TIME); + // 点击在UIAbility中申请权限 + let str = await getResourceString($r('app.string.req_permission_ability')); + await driver.assertComponentExist(ON.text(str)); + let reqPermissionInAbility = await driver.findComponent(ON.text(str)); + await reqPermissionInAbility.click(); + await driver.delayMs(DELAY_TIME); + // 点击仅使用期间允许 + str = await getResourceString($r('app.string.allowed_only_during_use')); + await driver.assertComponentExist(ON.text(str)); + let agreeBtn = await driver.findComponent(ON.text(str)); + await agreeBtn.click(); + await driver.delayMs(DELAY_TIME); + // 点击导航到EntryAbility + str = await getResourceString($r('app.string.return_entryability')); + await driver.assertComponentExist(ON.text(str)); + let backBtn = await driver.findComponent(ON.text(str)); + await backBtn.click(); + await driver.delayMs(DELAY_TIME); + // 点击检测权限 + str = await getResourceString($r('app.string.check_permission')); + await driver.assertComponentExist(ON.text(str)); + let checkPermissionBtn = await driver.findComponent(ON.text(str)); + await checkPermissionBtn.click(); + await driver.delayMs(DELAY_TIME); + Logger.info(BUNDLE + 'AllowPermissionInUIAbilityFunction_001 end'); + done(); + }) + }) +} \ No newline at end of file diff --git a/Security/RequestUserAuthorization/entry/src/ohosTest/ets/test/List.test.ets b/Security/RequestUserAuthorization/entry/src/ohosTest/ets/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..1eac52fcebe8958e19a7b8fed2e8f39c520a3e42 --- /dev/null +++ b/Security/RequestUserAuthorization/entry/src/ohosTest/ets/test/List.test.ets @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import abilityTest from './Ability.test'; + +export default function testsuite() { + abilityTest(); +} \ No newline at end of file diff --git a/Security/RequestUserAuthorization/entry/src/ohosTest/ets/utils/Logger.ts b/Security/RequestUserAuthorization/entry/src/ohosTest/ets/utils/Logger.ts new file mode 100644 index 0000000000000000000000000000000000000000..3a2078642ad8bf64b5900fdf62aabc678d9e2592 --- /dev/null +++ b/Security/RequestUserAuthorization/entry/src/ohosTest/ets/utils/Logger.ts @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import hilog from '@ohos.hilog'; + +class Logger { + private domain: number; + private prefix: string; + private format: string = '%{public}s'; + + constructor(prefix: string) { + this.prefix = prefix; + this.domain = 0xF811; + } + + debug(...args: string[]): void { + hilog.debug(this.domain, this.prefix, this.format, args); + } + + info(...args: string[]): void { + hilog.info(this.domain, this.prefix, this.format, args); + } + + warn(...args: string[]): void { + hilog.warn(this.domain, this.prefix, this.format, args); + } + + error(...args: string[]): void { + hilog.error(this.domain, this.prefix, this.format, args); + } +} + +export default new Logger('[Sample_RequestUserAuthorization]'); \ No newline at end of file diff --git a/Security/RequestUserAuthorization/entry/src/ohosTest/module.json5 b/Security/RequestUserAuthorization/entry/src/ohosTest/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..c3fd9dda3040d888d9d8b0b62bcb5d3b6fbeb614 --- /dev/null +++ b/Security/RequestUserAuthorization/entry/src/ohosTest/module.json5 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "module": { + "name": "entry_test", + "type": "feature", + "deviceTypes": [ + "default", + "tablet" + ], + "deliveryWithInstall": true, + "installationFree": false + } +} diff --git a/Security/RequestUserAuthorization/entry/src/ohosTest/resources/base/element/string.json b/Security/RequestUserAuthorization/entry/src/ohosTest/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..219973d467ba1f6fb6e93f3e7513a54f04f76b03 --- /dev/null +++ b/Security/RequestUserAuthorization/entry/src/ohosTest/resources/base/element/string.json @@ -0,0 +1,32 @@ +{ + "string": [ + { + "name": "check_permission", + "value": "检测权限" + }, + { + "name": "req_permission_ability", + "value": "在UIAbility中申请权限" + }, + { + "name": "req_permission_page", + "value": "在Page中申请权限" + }, + { + "name": "return_entryability", + "value": "导航到EntryAbility" + }, + { + "name": "return_main", + "value": "返回主页" + }, + { + "name": "cancel", + "value": "取消" + }, + { + "name": "allowed_only_during_use", + "value": "仅使用期间允许" + } + ] +} \ No newline at end of file diff --git a/Security/RequestUserAuthorization/entry/src/test/List.test.ets b/Security/RequestUserAuthorization/entry/src/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..f1186b1f53c3a70930921c5dbd1417332bec56c9 --- /dev/null +++ b/Security/RequestUserAuthorization/entry/src/test/List.test.ets @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import localUnitTest from './LocalUnit.test'; + +export default function testsuite() { + localUnitTest(); +} \ No newline at end of file diff --git a/Security/RequestUserAuthorization/entry/src/test/LocalUnit.test.ets b/Security/RequestUserAuthorization/entry/src/test/LocalUnit.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..7fc57c77dbf76d8df08a2b802a55b948e3fcf968 --- /dev/null +++ b/Security/RequestUserAuthorization/entry/src/test/LocalUnit.test.ets @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; + +export default function localUnitTest() { + describe('localUnitTest', () => { + // Defines a test suite. Two parameters are supported: test suite name and test suite function. + beforeAll(() => { + // Presets an action, which is performed only once before all test cases of the test suite start. + // This API supports only one parameter: preset action function. + }); + beforeEach(() => { + // Presets an action, which is performed before each unit test case starts. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: preset action function. + }); + afterEach(() => { + // Presets a clear action, which is performed after each unit test case ends. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: clear action function. + }); + afterAll(() => { + // Presets a clear action, which is performed after all test cases of the test suite end. + // This API supports only one parameter: clear action function. + }); + it('assertContain', 0, () => { + // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function. + let a = 'abc'; + let b = 'b'; + // Defines a variety of assertion methods, which are used to declare expected boolean conditions. + expect(a).assertContain(b); + expect(a).assertEqual(a); + }); + }); +} \ No newline at end of file diff --git a/Security/RequestUserAuthorization/hvigor/hvigor-config.json5 b/Security/RequestUserAuthorization/hvigor/hvigor-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..43beb743cbd25c3507b1cf8a744bf8197b3bf2fb --- /dev/null +++ b/Security/RequestUserAuthorization/hvigor/hvigor-config.json5 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "modelVersion": "5.0.0", + "dependencies": { + }, + "execution": { + // "analyze": "normal", /* Define the build analyze mode. Value: [ "normal" | "advanced" | false ]. Default: "normal" */ + // "daemon": true, /* Enable daemon compilation. Value: [ true | false ]. Default: true */ + // "incremental": true, /* Enable incremental compilation. Value: [ true | false ]. Default: true */ + // "parallel": true, /* Enable parallel compilation. Value: [ true | false ]. Default: true */ + // "typeCheck": false, /* Enable typeCheck. Value: [ true | false ]. Default: false */ + }, + "logging": { + // "level": "info" /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */ + }, + "debugging": { + // "stacktrace": false /* Disable stacktrace compilation. Value: [ true | false ]. Default: false */ + }, + "nodeOptions": { + // "maxOldSpaceSize": 8192 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process. Default: 8192*/ + // "exposeGC": true /* Enable to trigger garbage collection explicitly. Default: true*/ + } +} diff --git a/Security/RequestUserAuthorization/hvigorfile.ts b/Security/RequestUserAuthorization/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..4beb74fe5b573059b972acf9312d33ea1703c016 --- /dev/null +++ b/Security/RequestUserAuthorization/hvigorfile.ts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { appTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + plugins: [] /* Custom plugin to extend the functionality of Hvigor. */ +} diff --git a/Security/RequestUserAuthorization/oh-package.json5 b/Security/RequestUserAuthorization/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..93f097993a458e967d6d5239ea0580e79b5d6998 --- /dev/null +++ b/Security/RequestUserAuthorization/oh-package.json5 @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "modelVersion": "5.0.0", + "description": "Please describe the basic information.", + "dependencies": { + }, + "devDependencies": { + "@ohos/hypium": "1.0.19", + "@ohos/hamock": "1.0.0" + } +} diff --git a/Security/RequestUserAuthorization/ohosTest.md b/Security/RequestUserAuthorization/ohosTest.md new file mode 100644 index 0000000000000000000000000000000000000000..ca24e628b57b9ef3665f253df36bb316c62f8174 --- /dev/null +++ b/Security/RequestUserAuthorization/ohosTest.md @@ -0,0 +1,13 @@ +# 向用户申请权限测试用例归档 + +## 用例表 + +| 测试功能 | 预置条件 | 输入 | 预期输出 | 是否自动 | 测试结果 | +| ------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------ | -------- | -------- | +| 拉起应用 | 设备正常运行 | | 成功拉起应用 | 是 | Pass | +| 检测权限 | 成功拉起应用 | 点击“检测权限”按钮 | 提示框显示“权限未授予” | 是 | Pass | +| 在Page中申请权限 | 成功拉起应用,点击”在Page中申请权限“按钮后,成功进入“在Page中申请权限”界面,弹出申请权限弹窗 | 点击“取消”按钮->点击“返回主页”按钮->点击“检测权限”按钮 | 提示框显示“权限未授予” | 是 | Pass | +| 在Ability中申请权限 | 成功拉起应用,点击”在Ability中申请权限“按钮后,成功进入“在Page中申请权限”界面,弹出申请权限弹窗 | 点击“取消”按钮 | 出现二次申请权限弹窗 | 是 | Pass | +| 进行二次授权 | 成功拉起应用,点击”在Ability中申请权限“按钮后,成功进入“在Page中申请权限”界面,弹出申请权限弹窗,点击“取消按钮”,出现二次申请权限弹窗 | 点击“仅使用期间允许”按钮->点击“导航到EntryAbility”按钮->点击"检测权限按钮" | 提示框显示“未申请精确定位权限” | 是 | Pass | +| 授予所有权限 | 成功拉起应用,点击”在Ability中申请权限“按钮后,成功进入“在Page中申请权限”界面,弹出申请权限弹窗 | 点击“仅使用期间允许”按钮->点击“导航到EntryAbility”按钮->点击"检测权限按钮" | 提示框显示“权限已授予” | 是 | Pass | + diff --git a/Security/RequestUserAuthorization/screenshots/dialog.png b/Security/RequestUserAuthorization/screenshots/dialog.png new file mode 100644 index 0000000000000000000000000000000000000000..4c4a47b6e41984f9db484c20b25299c1a054a4f8 Binary files /dev/null and b/Security/RequestUserAuthorization/screenshots/dialog.png differ diff --git a/Security/RequestUserAuthorization/screenshots/main.png b/Security/RequestUserAuthorization/screenshots/main.png new file mode 100644 index 0000000000000000000000000000000000000000..330cd470e2e7316a57b726679d3d2a8b52ade8b3 Binary files /dev/null and b/Security/RequestUserAuthorization/screenshots/main.png differ diff --git a/Security/RequestUserAuthorization/screenshots/secondability.png b/Security/RequestUserAuthorization/screenshots/secondability.png new file mode 100644 index 0000000000000000000000000000000000000000..8f2ebef023e0b32edbef10c6691860ae56456c59 Binary files /dev/null and b/Security/RequestUserAuthorization/screenshots/secondability.png differ diff --git a/Security/RequestUserAuthorization/screenshots/seconddialog.png b/Security/RequestUserAuthorization/screenshots/seconddialog.png new file mode 100644 index 0000000000000000000000000000000000000000..12ffdc8a8026bbf011578aa5804573d3389eb3f4 Binary files /dev/null and b/Security/RequestUserAuthorization/screenshots/seconddialog.png differ diff --git a/Security/SecurityComponent/.gitignore b/Security/SecurityComponent/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..08d606210b3993e8f1f4535767bb3459b7b1d208 --- /dev/null +++ b/Security/SecurityComponent/.gitignore @@ -0,0 +1,13 @@ +/node_modules +/oh_modules +/local.properties +/.idea +**/build +/.hvigor +.cxx +/.clangd +/.clang-format +/.clang-tidy +**/.test +/.appanalyzer +/oh-package-lock.json5 \ No newline at end of file diff --git a/Security/SecurityComponent/AppScope/app.json5 b/Security/SecurityComponent/AppScope/app.json5 new file mode 100644 index 0000000000000000000000000000000000000000..3a606bfd52a238e3778f0a65e66793e19a576726 --- /dev/null +++ b/Security/SecurityComponent/AppScope/app.json5 @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "app": { + "bundleName": "com.samples.securitycomponent", + "vendor": "samples", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:app_icon", + "label": "$string:app_name" + } +} diff --git a/Security/SecurityComponent/AppScope/resources/base/element/string.json b/Security/SecurityComponent/AppScope/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..4745dc6c76c61623aff481b7cdf86a1772c4b95b --- /dev/null +++ b/Security/SecurityComponent/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "SecurityComponent" + } + ] +} diff --git a/Security/SecurityComponent/AppScope/resources/base/media/app_icon.png b/Security/SecurityComponent/AppScope/resources/base/media/app_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a39445dc87828b76fed6d2ec470dd455c45319e3 Binary files /dev/null and b/Security/SecurityComponent/AppScope/resources/base/media/app_icon.png differ diff --git a/Security/SecurityComponent/README.md b/Security/SecurityComponent/README.md new file mode 100644 index 0000000000000000000000000000000000000000..3f30a00ee15c4221534400c895c9f42d980e16fb --- /dev/null +++ b/Security/SecurityComponent/README.md @@ -0,0 +1,83 @@ +# 安全控件类型的UI控件(仅对系统应用开放) + +### 介绍 + +本示例提供了安全控件类型的UI控件,支撑应用开发者集成安全控件做临时授权场景,当用户实际点击了某种类型的安全控件时,会对应用进行相应的临时授权,减少权限弹窗对用户的干扰,同时提供更小的授权范围。 + +### 效果预览 + +| 主页 | Location | Paste | **Save** | +|:-----------------------------------:| :--------------------------------------------: |:---------------------------------------:| :------------------------------------: | +| ![main](screenshots/main.jpeg) | ![location](screenshots/location.jpeg) | ![paste](screenshots/paste.jpeg) | ![save](screenshots/save.jpeg) | + +使用说明 +1. 在主界面,点击“Location”按钮,进入“Location”界面,点击“当前位置”按钮,成功获取当前定位信息,并通过提示框显示。 + +2. 在主界面,点击“Paste”按钮,进入“Paste”界面,在文本输入框输入文字,全选剪切文字,点击“粘贴”按钮,获取剪贴板内容并显示在输入框中。 + +3. 在主界面,点击“Save”按钮,进入“Save”界面,点击“下载”按钮,将当前页面中的图片保存到本地的图库中。 + +### 工程目录 + +``` +SecurityComponent +├──entry/src/main +│ ├──ets +│ │ ├──entryability +│ │ │ └──EntryAbility.ets // 程序入口类 +| | ├──pages // 页面文件 +│ │ │ └──Index.ets // 首页 +│ │ └──securitycomponent // 组件文件 +│ │ └──page +│ │ ├──Location.ets // 位置服务安全控件界面 +│ │ ├──Paste.ets // 剪贴板安全控件界面 +│ │ └──Save.ets // 媒体库安全控件界面 +| ├──resources // 资源文件目录 +│ │ + +``` + +### 具体实现 + +* 本示例分为Location安全控件模块,剪贴板安全控件模块,媒体库安全控件模块。 + + * Location安全控件模块 + + * 使用LocationButton组件开发获取定位信息功能,在其点击回调onclick事件中调用geoLocationManager.getCurrentLocation()得到当前定位信息经纬度。 + * 接口参考:[@ohos.geoLocationManager](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-location-kit/js-apis-geoLocationManager.md#geolocationmanagergetcurrentlocation) + * 剪贴板安全控件模块 + + * 使用PasteButton组件开发获取剪贴板信息功能,在其点击回调onclick事件中调用pasteboard.getSystemPasteboard().getData()将文本复制到剪贴板中,使用pasteData.getPrimaryText()得到剪贴板内容。 + * 接口参考:[@ohos.pasteboard](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-basic-services-kit/js-apis-pasteboard.md) + * 媒体库安全控件模块 + + * 使用SaveButton组件开发保存图片到媒体库功能,在其点击回调onclick事件中调用photoAccessHelper.getPhotoAccessHelper()得到媒体库图片管理器helper, helper.createAsset()得到保存到媒体库图片的uri,使用resourceManager.getMediaContent()得到存放在Resources/base/media文件下的test.jpg图片内容,调用fs.open()和fs.write()将图片内容通过得到的uri写到媒体库中,最后fs.close()关闭文件。 + * 接口参考:[@ohos.file.photoAccessHelper](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-media-library-kit/js-apis-photoAccessHelper.md),[@ohos.file.fs](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-core-file-kit/js-apis-file-fs.md) + +### 相关权限 + +不涉及。 + +### 依赖 + +不涉及。 + +### 约束与限制 + +1. 本示例仅支持标准系统上运行,支持设备:华为手机。 +2. HarmonyOS系统:HarmonyOS 5.1.1 Release及以上。 +3. DevEco Studio版本:DevEco Studio 5.1.1 Release及以上。 +4. HarmonyOS SDK版本:HarmonyOS 5.1.1 Release及以上。 +5. 本示例需要使用系统权限的系统接口,需要使用Full SDK编译。使用Full SDK时需要手动从镜像站点获取,并在DevEco Studio中替换,具体操作可参考[替换指南](https://gitee.com/link?target=https%3A%2F%2Fdocs.openharmony.cn%2Fpages%2Fv3.2%2Fzh-cn%2Fapplication-dev%2Fquick-start%2Ffull-sdk-switch-guide.md%2F)。 + +### 下载 + +如需单独下载本工程,执行如下命令: + +``` +git init +git config core.sparsecheckout true +echo Security/SecurityComponent/ > .git/info/sparse-checkout +git remote add origin https://gitee.com/harmonyos_samples/guide-snippets.git +git pull origin master +``` \ No newline at end of file diff --git a/Security/SecurityComponent/build-profile.json5 b/Security/SecurityComponent/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..70ed2c0f0c839ab5534407497a376a399a1ac53a --- /dev/null +++ b/Security/SecurityComponent/build-profile.json5 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "app": { + "signingConfigs": [ + ], + "products": [ + { + "name": "default", + "signingConfig": "default", + "compatibleSdkVersion": "5.1.1(19)", + "targetSdkVersion": "5.1.1(19)", + "runtimeOS": "HarmonyOS", + "buildOption": { + "strictMode": { + "caseSensitiveCheck": true, + "useNormalizedOHMUrl": true + } + } + } + ], + "buildModeSet": [ + { + "name": "debug", + }, + { + "name": "release" + } + ] + }, + "modules": [ + { + "name": "entry", + "srcPath": "./entry", + "targets": [ + { + "name": "default", + "applyToProducts": [ + "default" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/Security/SecurityComponent/code-linter.json5 b/Security/SecurityComponent/code-linter.json5 new file mode 100644 index 0000000000000000000000000000000000000000..28586467ee7a761c737d8654a73aed6fddbc3c71 --- /dev/null +++ b/Security/SecurityComponent/code-linter.json5 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "files": [ + "**/*.ets" + ], + "ignore": [ + "**/src/ohosTest/**/*", + "**/src/test/**/*", + "**/src/mock/**/*", + "**/node_modules/**/*", + "**/oh_modules/**/*", + "**/build/**/*", + "**/.preview/**/*" + ], + "ruleSet": [ + "plugin:@performance/recommended", + "plugin:@typescript-eslint/recommended" + ], + "rules": { + } +} \ No newline at end of file diff --git a/Security/SecurityComponent/entry/.gitignore b/Security/SecurityComponent/entry/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..eadab4e1522296628f32a70228b2c758ecab4759 --- /dev/null +++ b/Security/SecurityComponent/entry/.gitignore @@ -0,0 +1,7 @@ +/node_modules +/oh_modules +/.preview +/build +/.cxx +/.test +/oh-package-lock.json5 \ No newline at end of file diff --git a/Security/SecurityComponent/entry/build-profile.json5 b/Security/SecurityComponent/entry/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..e7569e3056e27af38e9991b7ea73ec10f3ba8a05 --- /dev/null +++ b/Security/SecurityComponent/entry/build-profile.json5 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "apiType": "stageMode", + "buildOption": { + }, + "buildOptionSet": [ + { + "name": "release", + "arkOptions": { + "obfuscation": { + "ruleOptions": { + "enable": false, + "files": [ + "./obfuscation-rules.txt" + ] + } + } + } + }, + ], + "targets": [ + { + "name": "default" + }, + { + "name": "ohosTest", + } + ] +} \ No newline at end of file diff --git a/Security/SecurityComponent/entry/hvigorfile.ts b/Security/SecurityComponent/entry/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..a3d28cb60475cede46d0aa36973096d5544dbcd1 --- /dev/null +++ b/Security/SecurityComponent/entry/hvigorfile.ts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { hapTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + plugins: [] /* Custom plugin to extend the functionality of Hvigor. */ +} diff --git a/Security/SecurityComponent/entry/obfuscation-rules.txt b/Security/SecurityComponent/entry/obfuscation-rules.txt new file mode 100644 index 0000000000000000000000000000000000000000..272efb6ca3f240859091bbbfc7c5802d52793b0b --- /dev/null +++ b/Security/SecurityComponent/entry/obfuscation-rules.txt @@ -0,0 +1,23 @@ +# Define project specific obfuscation rules here. +# You can include the obfuscation configuration files in the current module's build-profile.json5. +# +# For more details, see +# https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/source-obfuscation-V5 + +# Obfuscation options: +# -disable-obfuscation: disable all obfuscations +# -enable-property-obfuscation: obfuscate the property names +# -enable-toplevel-obfuscation: obfuscate the names in the global scope +# -compact: remove unnecessary blank spaces and all line feeds +# -remove-log: remove all console.* statements +# -print-namecache: print the name cache that contains the mapping from the old names to new names +# -apply-namecache: reuse the given cache file + +# Keep options: +# -keep-property-name: specifies property names that you want to keep +# -keep-global-name: specifies names that you want to keep in the global scope + +-enable-property-obfuscation +-enable-toplevel-obfuscation +-enable-filename-obfuscation +-enable-export-obfuscation \ No newline at end of file diff --git a/Security/SecurityComponent/entry/oh-package.json5 b/Security/SecurityComponent/entry/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..c9cb6c8174858277c9b0d465a51547dcab16d5ff --- /dev/null +++ b/Security/SecurityComponent/entry/oh-package.json5 @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "name": "entry", + "version": "1.0.0", + "description": "Please describe the basic information.", + "main": "", + "author": "", + "license": "", + "dependencies": {} +} + diff --git a/Security/SecurityComponent/entry/src/main/ets/entryability/EntryAbility.ets b/Security/SecurityComponent/entry/src/main/ets/entryability/EntryAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..0f2f8b94aa24b0a50e272270e4e18b6df93ac5fd --- /dev/null +++ b/Security/SecurityComponent/entry/src/main/ets/entryability/EntryAbility.ets @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit'; +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { window } from '@kit.ArkUI'; + +export default class EntryAbility extends UIAbility { + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); + } + + onDestroy(): void { + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy'); + } + + onWindowStageCreate(windowStage: window.WindowStage): void { + // Main window is created, set main page for this ability + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); + + windowStage.loadContent('pages/Index', (err) => { + if (err.code) { + hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); + return; + } + hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.'); + }); + } + + onWindowStageDestroy(): void { + // Main window is destroyed, release UI related resources + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy'); + } + + onForeground(): void { + // Ability has brought to foreground + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground'); + } + + onBackground(): void { + // Ability has back to background + hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground'); + } +} diff --git a/Security/SecurityComponent/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets b/Security/SecurityComponent/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..b1e212947256c5533c7b06285a597c94f840a6e3 --- /dev/null +++ b/Security/SecurityComponent/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { BackupExtensionAbility, BundleVersion } from '@kit.CoreFileKit'; + +export default class EntryBackupAbility extends BackupExtensionAbility { + async onBackup() { + hilog.info(0x0000, 'testTag', 'onBackup ok'); + } + + async onRestore(bundleVersion: BundleVersion) { + hilog.info(0x0000, 'testTag', 'onRestore ok %{public}s', JSON.stringify(bundleVersion)); + } +} \ No newline at end of file diff --git a/Security/SecurityComponent/entry/src/main/ets/pages/Index.ets b/Security/SecurityComponent/entry/src/main/ets/pages/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..bba6109859107ea5769a5279a95411c4cd197ba8 --- /dev/null +++ b/Security/SecurityComponent/entry/src/main/ets/pages/Index.ets @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import router from '@ohos.router'; + +@Entry +@Component +struct Index { + private pageName: string [] = ['Location', 'Paste', 'Save']; + @State text: string = ''; + + openPage(pageName: string) { + router.pushUrl({ + url: 'securitycomponent/pages/' + pageName, + }); + } + + build() { + Column() { + ForEach(this.pageName, (item: string) => { + Button() { + Text(item + this.text) + .fontSize(19) + .fontColor(Color.White) + .fontWeight(FontWeight.Bold) + .padding({ left: 10, right: 10 }) + .width('80%') + .textAlign(TextAlign.Center) + } + .id(item) + .height(40) + .type(ButtonType.Capsule) + .backgroundColor('#0D9FFB') + .margin({ top: 20 }) + .onClick(() => { + this.openPage(item); + }) + }, (item: string) => JSON.stringify(item)) + } + .justifyContent(FlexAlign.Center) + .alignItems(HorizontalAlign.Center) + .width('100%') + .height('100%') + } +} \ No newline at end of file diff --git a/Security/SecurityComponent/entry/src/main/ets/securitycomponent/pages/Location.ets b/Security/SecurityComponent/entry/src/main/ets/securitycomponent/pages/Location.ets new file mode 100644 index 0000000000000000000000000000000000000000..db750608a74db28f18a0e3d933a0cb01effea392 --- /dev/null +++ b/Security/SecurityComponent/entry/src/main/ets/securitycomponent/pages/Location.ets @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// [Start use_location_button] +import { geoLocationManager } from '@kit.LocationKit'; +import { promptAction } from '@kit.ArkUI'; +import { BusinessError } from '@kit.BasicServicesKit'; + +// 获取当前位置信息 +function getCurrentLocationInfo() { + const requestInfo: geoLocationManager.LocationRequest = { + 'priority': geoLocationManager.LocationRequestPriority.FIRST_FIX, + 'scenario': geoLocationManager.LocationRequestScenario.UNSET, + 'timeInterval': 1, + 'distanceInterval': 0, + 'maxAccuracy': 0 + }; + try { + geoLocationManager.getCurrentLocation(requestInfo) + .then((location: geoLocationManager.Location) => { + promptAction.showToast({ message: JSON.stringify(location) }); + }) + .catch((err: BusinessError) => { + console.error(`Failed to get current location. Code is ${err.code}, message is ${err.message}`); + promptAction.showToast({ message: $r('app.string.get_location_failed') }); + }); + } catch (err) { + console.error(`Failed to get current location. Code is ${err.code}, message is ${err.message}`); + promptAction.showToast({ message: $r('app.string.get_location_failed') }); + } +} + +@Entry +@Component +struct Index { + build() { + Row() { + Column({ space: 10 }) { + LocationButton({ + icon: LocationIconStyle.LINES, + text: LocationDescription.CURRENT_LOCATION, + buttonType: ButtonType.Normal + }) + .padding({ + top: 12, + bottom: 12, + left: 24, + right: 24 + }) + .onClick((event: ClickEvent, result: LocationButtonOnClickResult) => { + if (result === LocationButtonOnClickResult.SUCCESS) { + // 免去权限申请和权限请求等环节,获得临时授权,获取位置信息授权 + getCurrentLocationInfo(); + } else { + promptAction.showToast({ message: $r('app.string.get_location_failed') }); + } + }) + } + .width('100%') + } + .height('100%') + .backgroundColor(0xF1F3F5) + } +} +// [End use_location_button] \ No newline at end of file diff --git a/Security/SecurityComponent/entry/src/main/ets/securitycomponent/pages/Paste.ets b/Security/SecurityComponent/entry/src/main/ets/securitycomponent/pages/Paste.ets new file mode 100644 index 0000000000000000000000000000000000000000..5cea35ea3d82ccce354045c51e2ab52bf61b57fd --- /dev/null +++ b/Security/SecurityComponent/entry/src/main/ets/securitycomponent/pages/Paste.ets @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// [Start use_paste_button] +import { pasteboard, BusinessError } from '@kit.BasicServicesKit'; + +@Entry +@Component +struct Index { + @State message: string = ''; + + build() { + Row() { + Column({ space: 10 }) { + TextInput({ placeholder: $r('app.string.input_verify_code'), text: this.message }) + PasteButton() + .padding({ + top: 12, + bottom: 12, + left: 24, + right: 24 + }) + .onClick((event: ClickEvent, result: PasteButtonOnClickResult) => { + if (PasteButtonOnClickResult.SUCCESS === result) { + pasteboard.getSystemPasteboard().getData((err: BusinessError, pasteData: pasteboard.PasteData) => { + if (err) { + console.error(`Failed to get paste data. Code is ${err.code}, message is ${err.message}`); + return; + } + // 剪贴板内容为 '123456' + this.message = pasteData.getPrimaryText(); + }); + } + }) + } + .width('100%') + } + .height('100%') + } +} +// [End use_paste_button] \ No newline at end of file diff --git a/Security/SecurityComponent/entry/src/main/ets/securitycomponent/pages/Save.ets b/Security/SecurityComponent/entry/src/main/ets/securitycomponent/pages/Save.ets new file mode 100644 index 0000000000000000000000000000000000000000..c1a6822bb43e8836e72925c9ece6ba56e353e9b9 --- /dev/null +++ b/Security/SecurityComponent/entry/src/main/ets/securitycomponent/pages/Save.ets @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// [Start use_save_button] +import { photoAccessHelper } from '@kit.MediaLibraryKit'; +import { fileIo } from '@kit.CoreFileKit'; +import { common } from '@kit.AbilityKit'; +import { promptAction } from '@kit.ArkUI'; +import { BusinessError } from '@kit.BasicServicesKit'; + +async function savePhotoToGallery(context: common.UIAbilityContext) { + let helper = photoAccessHelper.getPhotoAccessHelper(context); + try { + // onClick触发后5秒内通过createAsset接口创建图片文件,5秒后createAsset权限收回。 + let uri = await helper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'jpg'); + // 使用uri打开文件,可以持续写入内容,写入过程不受时间限制 + let file = await fileIo.open(uri, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE); + // $r('app.media.test')可以替换为开发者所需的图像资源文件 + context.resourceManager.getMediaContent($r('app.media.test').id, 0) + .then(async value => { + let media = value.buffer; + // 写到媒体库文件中 + await fileIo.write(file.fd, media); + await fileIo.close(file.fd); + promptAction.showToast({ message: $r('app.string.saved_in_photo') }); + }); + } catch (error) { + const err: BusinessError = error as BusinessError; + console.error(`Failed to save photo. Code is ${err.code}, message is ${err.message}`); + } +} + +@Entry +@Component +struct Index { + build() { + Row() { + Column({ space: 10 }) { + // $r('app.media.startIcon')需要替换为开发者所需的图像资源文件 + Image($r('app.media.test')) + .height(400) + .width('100%') + + SaveButton() + .padding({ + top: 12, + bottom: 12, + left: 24, + right: 24 + }) + .onClick(async (event: ClickEvent, result: SaveButtonOnClickResult) => { + if (result === SaveButtonOnClickResult.SUCCESS) { + const context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; + // 免去权限申请和权限请求等环节,获得临时授权,保存对应图片 + savePhotoToGallery(context); + } else { + promptAction.showToast({ message: $r('app.string.set_permission_failed') }); + } + }) + } + .width('100%') + } + .height('100%') + .backgroundColor(0xF1F3F5) + } +} +// [End use_save_button] \ No newline at end of file diff --git a/Security/SecurityComponent/entry/src/main/module.json5 b/Security/SecurityComponent/entry/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..4144486d1af4c03b0d767cce1cda86fc0d697f91 --- /dev/null +++ b/Security/SecurityComponent/entry/src/main/module.json5 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "module": { + "name": "entry", + "type": "entry", + "description": "$string:module_desc", + "mainElement": "EntryAbility", + "deviceTypes": [ + "default", + "tablet" + ], + "deliveryWithInstall": true, + "installationFree": false, + "pages": "$profile:main_pages", + "abilities": [ + { + "name": "EntryAbility", + "srcEntry": "./ets/entryability/EntryAbility.ets", + "description": "$string:EntryAbility_desc", + "icon": "$media:layered_image", + "label": "$string:EntryAbility_label", + "startWindowIcon": "$media:startIcon", + "startWindowBackground": "$color:start_window_background", + "exported": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ] + } + ], + "extensionAbilities": [ + { + "name": "EntryBackupAbility", + "srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets", + "type": "backup", + "exported": false, + "metadata": [ + { + "name": "ohos.extension.backup", + "resource": "$profile:backup_config" + } + ] + } + ] + } +} \ No newline at end of file diff --git a/Security/SecurityComponent/entry/src/main/resources/base/element/color.json b/Security/SecurityComponent/entry/src/main/resources/base/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..3c712962da3c2751c2b9ddb53559afcbd2b54a02 --- /dev/null +++ b/Security/SecurityComponent/entry/src/main/resources/base/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#FFFFFF" + } + ] +} \ No newline at end of file diff --git a/Security/SecurityComponent/entry/src/main/resources/base/element/string.json b/Security/SecurityComponent/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..160359841be7cabf65747992508b79d76ef84e9d --- /dev/null +++ b/Security/SecurityComponent/entry/src/main/resources/base/element/string.json @@ -0,0 +1,32 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "SecurityComponent" + }, + { + "name": "get_location_failed", + "value": "获取位置信息失败!" + }, + { + "name": "input_verify_code", + "value": "请输入验证码" + }, + { + "name": "saved_in_photo", + "value": "已保存至相册!" + }, + { + "name": "set_permission_failed", + "value": "设置权限失败!" + } + ] +} \ No newline at end of file diff --git a/Security/SecurityComponent/entry/src/main/resources/base/media/background.png b/Security/SecurityComponent/entry/src/main/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..f939c9fa8cc8914832e602198745f592a0dfa34d Binary files /dev/null and b/Security/SecurityComponent/entry/src/main/resources/base/media/background.png differ diff --git a/Security/SecurityComponent/entry/src/main/resources/base/media/foreground.png b/Security/SecurityComponent/entry/src/main/resources/base/media/foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..4483ddad1f079e1089d685bd204ee1cfe1d01902 Binary files /dev/null and b/Security/SecurityComponent/entry/src/main/resources/base/media/foreground.png differ diff --git a/Security/SecurityComponent/entry/src/main/resources/base/media/layered_image.json b/Security/SecurityComponent/entry/src/main/resources/base/media/layered_image.json new file mode 100644 index 0000000000000000000000000000000000000000..fb49920440fb4d246c82f9ada275e26123a2136a --- /dev/null +++ b/Security/SecurityComponent/entry/src/main/resources/base/media/layered_image.json @@ -0,0 +1,7 @@ +{ + "layered-image": + { + "background" : "$media:background", + "foreground" : "$media:foreground" + } +} \ No newline at end of file diff --git a/Security/SecurityComponent/entry/src/main/resources/base/media/startIcon.png b/Security/SecurityComponent/entry/src/main/resources/base/media/startIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..205ad8b5a8a42e8762fbe4899b8e5e31ce822b8b Binary files /dev/null and b/Security/SecurityComponent/entry/src/main/resources/base/media/startIcon.png differ diff --git a/Security/SecurityComponent/entry/src/main/resources/base/media/test.jpg b/Security/SecurityComponent/entry/src/main/resources/base/media/test.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e1831c7f9c88afb039d71bfdee61af67c41b1767 Binary files /dev/null and b/Security/SecurityComponent/entry/src/main/resources/base/media/test.jpg differ diff --git a/Security/SecurityComponent/entry/src/main/resources/base/profile/backup_config.json b/Security/SecurityComponent/entry/src/main/resources/base/profile/backup_config.json new file mode 100644 index 0000000000000000000000000000000000000000..78f40ae7c494d71e2482278f359ec790ca73471a --- /dev/null +++ b/Security/SecurityComponent/entry/src/main/resources/base/profile/backup_config.json @@ -0,0 +1,3 @@ +{ + "allowToBackupRestore": true +} \ No newline at end of file diff --git a/Security/SecurityComponent/entry/src/main/resources/base/profile/main_pages.json b/Security/SecurityComponent/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..c46f95159f4e90d31b6253e8ac78740c5ca08f84 --- /dev/null +++ b/Security/SecurityComponent/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,8 @@ +{ + "src": [ + "pages/Index", + "securitycomponent/pages/Location", + "securitycomponent/pages/Paste", + "securitycomponent/pages/Save" + ] +} diff --git a/Security/SecurityComponent/entry/src/main/resources/en_US/element/string.json b/Security/SecurityComponent/entry/src/main/resources/en_US/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..f247beb3ef35791f6a203ccd3886b86627c4f025 --- /dev/null +++ b/Security/SecurityComponent/entry/src/main/resources/en_US/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "securityComponent" + } + ] +} \ No newline at end of file diff --git a/Security/SecurityComponent/entry/src/main/resources/zh_CN/element/string.json b/Security/SecurityComponent/entry/src/main/resources/zh_CN/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..4aa85070675744fee81dfbd936f1cf9171116457 --- /dev/null +++ b/Security/SecurityComponent/entry/src/main/resources/zh_CN/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "模块描述" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "安全组件" + } + ] +} \ No newline at end of file diff --git a/Security/SecurityComponent/entry/src/mock/mock-config.json5 b/Security/SecurityComponent/entry/src/mock/mock-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..b9a78e201535765168a92d3543c690273ecdc019 --- /dev/null +++ b/Security/SecurityComponent/entry/src/mock/mock-config.json5 @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ +} \ No newline at end of file diff --git a/Security/SecurityComponent/entry/src/ohosTest/ets/test/Ability.test.ets b/Security/SecurityComponent/entry/src/ohosTest/ets/test/Ability.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..b7e9f1b20ef9385d3b2dee79c239df97236ca669 --- /dev/null +++ b/Security/SecurityComponent/entry/src/ohosTest/ets/test/Ability.test.ets @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry'; +import { describe, it, expect } from '@ohos/hypium'; +import { Driver, ON } from '@ohos.UiTest'; +import Logger from '../utils/Logger'; + +const BUNDLE = 'SecurityComponent_'; +const DELAY_TIME = 1000; +let abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator(); +let manage = abilityDelegator.getAppContext().resourceManager; + +async function getResourceString(resource: Resource): Promise { + let text = await manage.getStringValue(resource); + return text; +} + +export default function abilityTest() { + let driver = Driver.create(); + describe('SecurityComponentTest', (done: Function) => { + /** + * 拉起应用 + */ + it(BUNDLE + 'StartAbility_001', 0, async (done: Function) => { + Logger.info(BUNDLE + 'StartAbility_001 begin'); + try { + await abilityDelegator.startAbility({ + bundleName: 'com.samples.securitycomponent', + abilityName: 'EntryAbility' + }) + done(); + } catch (exception) { + Logger.info(`StartAbility_001 exception = ${JSON.stringify(exception)}`); + expect().assertFail(); + done(); + } + Logger.info(BUNDLE + 'StartAbility_001 end'); + }) + /** + * 获取定位信息 + */ + it(BUNDLE + 'GetLocation_001', 0, async (done: Function) => { + Logger.info(BUNDLE + 'GetLocation_001 begin'); + await driver.delayMs(DELAY_TIME); + // 点击Location + await driver.assertComponentExist(ON.id('Location')); + let location = await driver.findComponent(ON.id('Location')); + await location.click(); + await driver.delayMs(DELAY_TIME); + // 点击LocationButton获取定位信息 + await driver.assertComponentExist(ON.type('LocationButton')); + let locationButton = await driver.findComponent(ON.type('LocationButton')); + await locationButton.click(); + await driver.delayMs(DELAY_TIME); + // 点击允许 + let str = await getResourceString($r('app.string.admit')); + await driver.assertComponentExist(ON.text(str)); + let button = await driver.findComponent(ON.text(str)); + await button.click(); + await driver.delayMs(DELAY_TIME * 5); + // 返回 + await driver.pressBack(); + await driver.delayMs(DELAY_TIME); + Logger.info(BUNDLE + 'GetLocation_001 end'); + done(); + }) + + /** + * 获取剪贴板内容 + */ + it(BUNDLE + 'GetPasteContent_001', 0, async (done: Function) => { + Logger.info(BUNDLE + 'GetPasteContent_001 begin'); + await driver.delayMs(DELAY_TIME); + // 点击Paste + await driver.assertComponentExist(ON.id('Paste')); + let paste = await driver.findComponent(ON.id('Paste')); + await paste.click(); + await driver.delayMs(DELAY_TIME); + // 点击TextInput输入'123456'文本 + await driver.assertComponentExist(ON.type('TextInput')); + let textInput = await driver.findComponent(ON.type('TextInput')); + await textInput.inputText('123456'); + await textInput.longClick(); + await driver.delayMs(DELAY_TIME); + // 点击全选按钮 + let str = await getResourceString($r('app.string.select_all')); + await driver.assertComponentExist(ON.text(str)); + let selectButton = await driver.findComponent(ON.text(str)); + await selectButton.click(); + await driver.delayMs(DELAY_TIME); + // 点击剪切选项 + str = await getResourceString($r('app.string.cut')); + await driver.assertComponentExist(ON.text(str)); + let cutButton = await driver.findComponent(ON.text(str)); + await cutButton.click(); + await driver.delayMs(DELAY_TIME); + // 隐藏输入法 + await driver.pressBack(); + await driver.delayMs(DELAY_TIME); + // 点击pasteButton 粘贴'123456'文本 + await driver.assertComponentExist(ON.type('PasteButton')); + let copyButton = await driver.findComponent(ON.type('PasteButton')); + await copyButton.click(); + await driver.delayMs(DELAY_TIME); + // 返回主页 + await driver.pressBack(); + await driver.delayMs(DELAY_TIME); + Logger.info(BUNDLE + 'GetPasteContent_001 end'); + done(); + }) + + /** + * 保存图片到媒体库 + */ + it(BUNDLE + 'Save_001', 0, async (done: Function) => { + Logger.info(BUNDLE + 'Save_001 begin'); + await driver.delayMs(DELAY_TIME); + // 点击Save + await driver.assertComponentExist(ON.id('Save')); + let save = await driver.findComponent(ON.id('Save')); + await save.click(); + await driver.delayMs(DELAY_TIME); + // 点击LocationButton获取定位信息 + await driver.assertComponentExist(ON.type('SaveButton')); + let saveButton = await driver.findComponent(ON.type('SaveButton')); + await saveButton.click(); + await driver.delayMs(DELAY_TIME); + // 点击允许 + let str = await getResourceString($r('app.string.admit')); + await driver.assertComponentExist(ON.text(str)); + let Button = await driver.findComponent(ON.text(str)); + await Button.click(); + await driver.delayMs(DELAY_TIME); + // 返回 + await driver.pressBack(); + await driver.delayMs(DELAY_TIME); + Logger.info(BUNDLE + 'Save_001 end'); + done(); + }) + }) +} + diff --git a/Security/SecurityComponent/entry/src/ohosTest/ets/test/List.test.ets b/Security/SecurityComponent/entry/src/ohosTest/ets/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..1eac52fcebe8958e19a7b8fed2e8f39c520a3e42 --- /dev/null +++ b/Security/SecurityComponent/entry/src/ohosTest/ets/test/List.test.ets @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import abilityTest from './Ability.test'; + +export default function testsuite() { + abilityTest(); +} \ No newline at end of file diff --git a/Security/SecurityComponent/entry/src/ohosTest/ets/utils/Logger.ts b/Security/SecurityComponent/entry/src/ohosTest/ets/utils/Logger.ts new file mode 100644 index 0000000000000000000000000000000000000000..c0672b968e8e940b62d5b943f31f9a9aa7e0fbc1 --- /dev/null +++ b/Security/SecurityComponent/entry/src/ohosTest/ets/utils/Logger.ts @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import hilog from '@ohos.hilog'; + +class Logger { + private domain: number; + private prefix: string; + private format: string = '%{public}s'; + + constructor(prefix: string) { + this.prefix = prefix; + this.domain = 0xF811; + } + + debug(...args: string[]): void { + hilog.debug(this.domain, this.prefix, this.format, args); + } + + info(...args: string[]): void { + hilog.info(this.domain, this.prefix, this.format, args); + } + + warn(...args: string[]): void { + hilog.warn(this.domain, this.prefix, this.format, args); + } + + error(...args: string[]): void { + hilog.error(this.domain, this.prefix, this.format, args); + } +} + +export default new Logger('[Sample_SecurityComponent]'); \ No newline at end of file diff --git a/Security/SecurityComponent/entry/src/ohosTest/module.json5 b/Security/SecurityComponent/entry/src/ohosTest/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..924e61edf7b81c0583debc543425a2cb893c913b --- /dev/null +++ b/Security/SecurityComponent/entry/src/ohosTest/module.json5 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "module": { + "name": "entry_test", + "type": "feature", + "deviceTypes": [ + "default", + "tablet" + ], + "deliveryWithInstall": true, + "installationFree": false, + } +} \ No newline at end of file diff --git a/Security/SecurityComponent/entry/src/ohosTest/resources/base/element/string.json b/Security/SecurityComponent/entry/src/ohosTest/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..078f1487cf82614f4df507fcafd7c941ea7a5d3b --- /dev/null +++ b/Security/SecurityComponent/entry/src/ohosTest/resources/base/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "admit", + "value": "允许" + }, + { + "name": "select_all", + "value": "全选" + }, + { + "name": "cut", + "value": "剪切" + } + ] +} \ No newline at end of file diff --git a/Security/SecurityComponent/entry/src/test/List.test.ets b/Security/SecurityComponent/entry/src/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..f1186b1f53c3a70930921c5dbd1417332bec56c9 --- /dev/null +++ b/Security/SecurityComponent/entry/src/test/List.test.ets @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import localUnitTest from './LocalUnit.test'; + +export default function testsuite() { + localUnitTest(); +} \ No newline at end of file diff --git a/Security/SecurityComponent/entry/src/test/LocalUnit.test.ets b/Security/SecurityComponent/entry/src/test/LocalUnit.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..7fc57c77dbf76d8df08a2b802a55b948e3fcf968 --- /dev/null +++ b/Security/SecurityComponent/entry/src/test/LocalUnit.test.ets @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; + +export default function localUnitTest() { + describe('localUnitTest', () => { + // Defines a test suite. Two parameters are supported: test suite name and test suite function. + beforeAll(() => { + // Presets an action, which is performed only once before all test cases of the test suite start. + // This API supports only one parameter: preset action function. + }); + beforeEach(() => { + // Presets an action, which is performed before each unit test case starts. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: preset action function. + }); + afterEach(() => { + // Presets a clear action, which is performed after each unit test case ends. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: clear action function. + }); + afterAll(() => { + // Presets a clear action, which is performed after all test cases of the test suite end. + // This API supports only one parameter: clear action function. + }); + it('assertContain', 0, () => { + // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function. + let a = 'abc'; + let b = 'b'; + // Defines a variety of assertion methods, which are used to declare expected boolean conditions. + expect(a).assertContain(b); + expect(a).assertEqual(a); + }); + }); +} \ No newline at end of file diff --git a/Security/SecurityComponent/hvigor/hvigor-config.json5 b/Security/SecurityComponent/hvigor/hvigor-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..43beb743cbd25c3507b1cf8a744bf8197b3bf2fb --- /dev/null +++ b/Security/SecurityComponent/hvigor/hvigor-config.json5 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "modelVersion": "5.0.0", + "dependencies": { + }, + "execution": { + // "analyze": "normal", /* Define the build analyze mode. Value: [ "normal" | "advanced" | false ]. Default: "normal" */ + // "daemon": true, /* Enable daemon compilation. Value: [ true | false ]. Default: true */ + // "incremental": true, /* Enable incremental compilation. Value: [ true | false ]. Default: true */ + // "parallel": true, /* Enable parallel compilation. Value: [ true | false ]. Default: true */ + // "typeCheck": false, /* Enable typeCheck. Value: [ true | false ]. Default: false */ + }, + "logging": { + // "level": "info" /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */ + }, + "debugging": { + // "stacktrace": false /* Disable stacktrace compilation. Value: [ true | false ]. Default: false */ + }, + "nodeOptions": { + // "maxOldSpaceSize": 8192 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process. Default: 8192*/ + // "exposeGC": true /* Enable to trigger garbage collection explicitly. Default: true*/ + } +} diff --git a/Security/SecurityComponent/hvigorfile.ts b/Security/SecurityComponent/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..4beb74fe5b573059b972acf9312d33ea1703c016 --- /dev/null +++ b/Security/SecurityComponent/hvigorfile.ts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { appTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + plugins: [] /* Custom plugin to extend the functionality of Hvigor. */ +} diff --git a/Security/SecurityComponent/oh-package.json5 b/Security/SecurityComponent/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..93f097993a458e967d6d5239ea0580e79b5d6998 --- /dev/null +++ b/Security/SecurityComponent/oh-package.json5 @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "modelVersion": "5.0.0", + "description": "Please describe the basic information.", + "dependencies": { + }, + "devDependencies": { + "@ohos/hypium": "1.0.19", + "@ohos/hamock": "1.0.0" + } +} diff --git a/Security/SecurityComponent/ohosTest.md b/Security/SecurityComponent/ohosTest.md new file mode 100644 index 0000000000000000000000000000000000000000..f1dd06475c698ea844712e308d4a349edcb0cf42 --- /dev/null +++ b/Security/SecurityComponent/ohosTest.md @@ -0,0 +1,11 @@ +# 安全控件测试用例归档 + +## 用例表 + +| 测试功能 | 预置条件 | 输入 | 预期输出 | 是否自动 | 测试结果 | +| -------------- | ------------------------------------------------------------ | ------------------ | ---------------------------- | -------- | -------- | +| 拉起应用 | 设备正常运行 | | 成功拉起应用 | 是 | Pass | +| 获取定位信息 | 成功拉起应用,点击”Location“按钮后,成功进入“Location”界面 | 点击“当前位置”按钮 | 提示框显示获取位置信息失败 | 是 | Pass | +| 剪切输入框内容 | 成功拉起应用,点击”Paste“按钮后,成功进入“Paste”界面,拉起输入法,输入文本后长按输入框,点击“全选”按钮 | 点击“剪切”按钮 | 文本被剪切,输入框清除文本 | 是 | Pass | +| 获取剪贴板内容 | 成功拉起应用,点击”Paste“按钮后,成功进入“Paste”界面,成功得到输入文本 | 点击“粘贴”按钮 | 剪切的文本信息出现在文本框中 | 是 | Pass | +| 保存图片 | 成功拉起应用,点击”SaveButton“按钮后,成功进入“SaveButton”界面 | 点击“下载”按钮 | 弹出提示框,文件保存成功 | 是 | Pass | \ No newline at end of file diff --git a/Security/SecurityComponent/screenshots/location.jpeg b/Security/SecurityComponent/screenshots/location.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..914eaa22f8a651b13f44ba47e9b12fd7eacbc490 Binary files /dev/null and b/Security/SecurityComponent/screenshots/location.jpeg differ diff --git a/Security/SecurityComponent/screenshots/main.jpeg b/Security/SecurityComponent/screenshots/main.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..ba804573ab5b80fa80ab6f8cfe4b988b8f33f397 Binary files /dev/null and b/Security/SecurityComponent/screenshots/main.jpeg differ diff --git a/Security/SecurityComponent/screenshots/paste.jpeg b/Security/SecurityComponent/screenshots/paste.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..470b8f250c98f64050721924458a3eb0f9b77cfe Binary files /dev/null and b/Security/SecurityComponent/screenshots/paste.jpeg differ diff --git a/Security/SecurityComponent/screenshots/save.jpeg b/Security/SecurityComponent/screenshots/save.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..6fcc8a8d531a2ad1b563b22f100a77a6d93462c7 Binary files /dev/null and b/Security/SecurityComponent/screenshots/save.jpeg differ