IT评测·应用市场-qidao123.com
标题:
鸿蒙_底子
[打印本页]
作者:
铁佛
时间:
2025-3-9 18:01
标题:
鸿蒙_底子
HarmonyOS底子
页面跳转
import { router } from '@kit.ArkUI'
Button('去首页').onClick(()=>{
router.pushUrl({ // 普通跳转,可以返回
url:'pages/Index'
})
})
Button('登录').onClick(()=>{
router.replaceUrl({ // 替换跳转,无法返回,不追加页面栈
url:'pages/Index'
})
})
返回
router.back()
复制代码
页面栈
存储运行时的页面,先进后出
页面栈的最大容量为32个页面
// 获取页面栈的长度
router.getLength()
// 清空页面栈
router.clear()
复制代码
路由模式
Standard:无论之前是否添加过,不停添加到页面栈(默认利用)
Single:假如目标页面已存在,会将已有的最近同url页面移到栈顶(看情况利用)
router.pushUrl({
url:'pages/Index'
},router.RouterMode.Single)
复制代码
路由传参
import { router } from '@kit.ArkUI'
@Entry
@Component
struct Parent {
@State
username:string=''
build() {
Column() {
Text('登录页面')
.fontSize(40)
TextInput({placeholder:'请输入用户名~',text:$$this.username})
Button('登录')
.onClick(()=>{
router.pushUrl({
url:'pages/Index',
params:{
username:this.username,
msg:'测试消息'
}
})
})
}
}
}
复制代码
import { router } from '@kit.ArkUI'
interface ParamsObj{
username:string
msg:string
}
@Entry
@Component
struct Index {
@State
myName: string = ''
// 一进入页面,就会执行的函数 => 生命周期函数
aboutToAppear(): void {
console.log('传递过来的数据', JSON.stringify(router.getParams()))
const params = router.getParams() as ParamsObj
this.myName = params.username
}
build() {
Column() {
Text('首页')
.fontSize(40)
Text('姓名' + this.myName)
}
.height('100%')
.width('100%')
}
}
复制代码
传递过来的数据 {"username":"cnyunos","msg":"测试消息"}
复制代码
时间
安装
ohpm install dayjs
复制代码
利用
[/code] [size=3]生命周期[/size]
组件和页面在创建、表现、烧毁的这一整个过程中,会自动实行的一系列函数(生命周期钩子)
让开发者有时机在特定的阶段运行自己的代码
带@Entry的就是页面,不带的就是组件
页面和组件都有,进入的时候,先实行页面的,再实行组件的。退出就会先实行组件的,再实行页面的
[code]aboutToAppear(): void {} //创建组件实例后执行,可以修改状态变量
aboutToDisappear(): void {} // 组件实例xiao前执行,不允许修改状态变量
复制代码
仅@Entry修饰的页面组件生效
onPageShow(): void {} // 页面每次显示触发(路由过程、应用进入前后台)
onPageHide(): void {} // 页面每次隐藏触发(路由过程、应用进入前后台)
onBackPress(): boolean|void {} //点击返回触发(return true 阻止返回键默认返回效果)
复制代码
onBackPress(): boolean|void {
return true // 会导致,点了返回也不返回
}
复制代码
Stage模型
官方文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/application-component-configuration-stage-V5
应用包名配置
应用需要在工程的AppScope目录下的app.json5配置文件中配置bundleName标签,该标签用于标识应用的唯一性。推荐采用反域名情势命名(如com.example.demo,建议第一级为域名后缀com,第二级为厂商/个人名,第三级为应用名,也可以多级)
假如需要在桌面表现UIAbility图标,除了需要配置icon与label字段,还需要在skills标签下面的entities中添加"entity.system.home"、actions中添加"ohos.want.action.home"。
"icon": "$media:my_app",
"label": "$string:EntryAbility_label",
复制代码
icon 可以直接修改,图片放在 entity > src > main > resources > base > media
label 需要修改 entity > src > main > resources > base > element > string.json
假如没有 Open editor 就鼠标右键当前文件 列选择模式
Ability之间的跳转
let want:Want = {
deviceId:'', // 跳转到哪部手机,为空表示当前手机
bundleName:'com.example.myapplication', // 当前程序包名
abilityName:'EntryAbility1' // 目标ability
};(getContext() as common.UIAbilityContext).startAbility(want)
复制代码
'bundleName': 在AppScope > app.json5里面
'abilityName': 在src > main > module.json5里面
复制代码
Stage模型 - UIAbility 组件
// 如果有多个Ability,谁的后面加了这个,谁就默认展示,然后再配置下面的来觉得展示哪个页面
"exported": true,
"skills": [
{
"entities": [
"entity.system.home"
],
"actions": [
"action.system.home"
]
}
]
复制代码
export default class EntryAbility extends UIAbility {
......
onWindowStageCreate(windowStage: window.WindowStage): void {
......
// 默认加载页面
windowStage.loadContent('pages/Index', (err) => {......})
}
}
复制代码
新建 Ability
新建模块
Stage模型 - UIAbility 组件的生命周期
当用户打开、切换和返回到对应应用时,应用中的UIAbility实例会在其生命周期的差别状态之间转换。
onCreate:Ability创建时回调,实行初始化业务逻辑操作。
onDestory: Ability烧毁时回调,实行资源清算等操作。
onForeground:当应用从后台转到前台时触发。
onBackground:当应用从前台转到后台时触发
LocalStorage - UIAbility内状态
官方文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/arkts-localstorage-V5
一个UIAbility有多个页面需要共享数据,就用LocalStorage
两种数据界说方式:
自己界说一个ets文件,界说好数据之后导出
将数据界说到 EntryAbility 文件,再共享到各个页面
const data: Record<string, ResourceColor> = {
'name': '陈丰芸',
'picture': $r('app.media.s9'),
'colour': Color.Yellow
}
export const localInfo = new LocalStorage(data)
复制代码
import { localInfo } from './LocalStorageDataClass';
import { router } from '@kit.ArkUI';
@Entry(localInfo)
@Component
struct Index {
@LocalStorageLink('name')
name:ResourceColor = ''
@LocalStorageLink('picture')
picture:ResourceColor = ''
@LocalStorageLink('colour')
colour:ResourceColor = ''
build() {
Column(){
Text('默认首页')
.fontSize(50)
.fontWeight(FontWeight.Bold)
Image(this.picture as Resource)
.width('100%')
Row(){
Text('姓名:')
TextInput({text:$$this.name})
}
.backgroundColor(this.colour)
Button('去自定义页面')
.onClick(()=>{
router.pushUrl({
url:'pages/DemoPage'
})
})
}
.height('100%')
.width('100%')
}
}
复制代码
import { localInfo } from './LocalStorageDataClass';
import { router } from '@kit.ArkUI';
@Entry(localInfo)
@Component
struct DemoPage {
@LocalStorageLink('name')
name:ResourceColor = ''
@LocalStorageLink('picture')
picture:ResourceColor = ''
@LocalStorageLink('colour')
colour:ResourceColor = ''
build() {
Column(){
Text('自定义首页')
.fontSize(50)
.fontWeight(FontWeight.Bold)
Image(this.picture as Resource)
.width('100%')
Row(){
Text('姓名:')
TextInput({text:$$this.name})
}
.backgroundColor(this.colour)
Button('回到首页')
.onClick(()=>router.back())
}
.height('100%')
.width('100%')
}
}
复制代码
第二种
onWindowStageCreate(windowStage: window.WindowStage): void {
const data: Record<string, ResourceColor> = {
'name': '陈丰芸',
'picture': $r('app.media.s9'),
'colour': Color.Yellow
}
const localInfo = new LocalStorage(data)
windowStage.loadContent('pages/Index',localInfo);
}
复制代码
import { router } from '@kit.ArkUI';
let localInfo = LocalStorage.GetShared()
@Entry(localInfo)
@Component
struct Index {
@LocalStorageLink('name')
name:ResourceColor = ''
@LocalStorageLink('picture')
picture:ResourceColor = ''
@LocalStorageLink('colour')
colour:ResourceColor = ''
build() {
Column(){
Text('默认首页')
.fontSize(50)
.fontWeight(FontWeight.Bold)
Image(this.picture as Resource)
.width('100%')
Row(){
Text('姓名:')
TextInput({text:$$this.name})
}
.backgroundColor(this.colour)
Button('去自定义页面')
.onClick(()=>{
router.pushUrl({
url:'pages/DemoPage'
})
})
}
.height('100%')
.width('100%')
}
}
复制代码
import { router } from '@kit.ArkUI';
@Entry(LocalStorage.GetShared())
@Component
struct DemoPage {
@LocalStorageLink('name')
name:ResourceColor = ''
@LocalStorageLink('picture')
picture:ResourceColor = ''
@LocalStorageLink('colour')
colour:ResourceColor = ''
build() {
Column(){
Text('自定义首页')
.fontSize(50)
.fontWeight(FontWeight.Bold)
Image(this.picture as Resource)
.width('100%')
Row(){
Text('姓名:')
TextInput({text:$$this.name})
}
.backgroundColor(this.colour)
Button('回到首页')
.onClick(()=>router.back())
}
.height('100%')
.width('100%')
}
}
复制代码
AppStorage - 应用状态
import { router } from '@kit.ArkUI'
import { common, Want } from '@kit.AbilityKit'
@Entry
@Component
struct DemoPage {
@State
username: string = ""
@State
password: string = ""
login(){
const userInfo:Record<string,string>={
'name':'陈丰芸',
'age':'18'
}
AppStorage.setOrCreate('userInfo',userInfo)
// router.pushUrl({
// url:'pages/Index'
// })
let want:Want = {
deviceId:'',
bundleName:'com.example.myapplication',
abilityName:'EntryAbility1'
};(getContext() as common.UIAbilityContext).startAbility(want)
}
build() {
Column({space:20}){
TextInput({placeholder:'请输入用户名',text:$$this.username})
TextInput({placeholder:'请输入密码',text:$$this.password}).type(InputType.Password)
Button('登录').width('100%')
.onClick(()=>{
this.login()
})
}
.height('100%')
.width('100%')
}
}
复制代码
import { router } from '@kit.ArkUI'
@Entry
@Component
struct Index {
// 用法一
@StorageLink('userInfo')
userInfo:Record<string,string>={}
// 用法二
// @State
// userInfo:Record<string,string>={}
// aboutToAppear(): void {
// const userInfo = AppStorage.get<Record<string,string>>('userInfo')
// this.userInfo = userInfo!
// }
build() {
Column({space:20}){
Row(){
Text('姓名:')
TextInput({text:this.userInfo.name})
}
Row(){
Text('年龄')
TextInput({text:this.userInfo.age})
}
Button('退出').onClick(()=>{
// AppStorage.set('userInfo',null)
router.back()
})
}
.height('100%')
.width('100%')
}
}
复制代码
AppStorage.setOrCreate(“”, T) // 创建大概设置某个字段的属性
AppStorage.get(“”) // 获取的全局状态类型
假如遇到获取数据的类型为空,可以用if判断,也可以用非空断言来解决
StorageLink . - 直接修改-自动同步到全局状态
StorageProp- 可以改,只会在当前组件生效,只是改的全局状态的副本,不会对全局状态产生影响
PersistentStorage - 长期化存储UI状态
PersistentStorage.PersistProp(‘属性名’, 值)
PersistentStorage.persistProp('message','666666')
@Entry
@Component
struct Index {
@StorageLink('message')
message: string = '默认首页';
build() {
Column(){
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
Button('按钮')
.onClick(()=>{
AppStorage.setOrCreate('message','123456')
})
}
.height('100%')
.width('100%')
}
}
复制代码
步伐实行先取PersistentStorage的值,假如没有再取AppStorage的值,末了才是默认值
在取PersistentStorage值过程中,先去磁盘上读,没有读到,就展示默认值
第一次,磁盘内里肯定是没有的,于是就展示默认值,点击按钮之后,会修改message的值,写入磁盘,下次再打开应用,磁盘有内容,于是就展示123456
案例(反面追加)
在 EntryAbility 里面加,页面一启动的时候就会执行
windowStage.loadContent('/pages/Index'.slice(1), (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.');
// 持久化
PersistentStorage.persistProp('isHidePrivacy', false)
})
------------------------------------------------------------------------
页面中使用
@StorageLink('isHidePrivacy') isHidePrivacy: boolean = false
----
@StorageLink 可以双向绑定,需要给默认值
复制代码
preferences - 状态长期化
import preferences from '@ohos.data.preferences'
import { Context } from '@kit.AbilityKit'
export class PreferencesClass {
// 默认存储仓库
static defaultStore: string = 'DEFAULT_STORE'
// 字段名
static tokenkey: string = 'TOKEN_KEY'
// 给字段添加set方法 仓库名字由外面传递,没有传就用默认值
static setToken(content: Context, token: string, storeName: string = PreferencesClass.defaultStore) {
// 先拿到仓库
const store = preferences.getPreferencesSync(content, { name: storeName })
// 再拿到key
store.putSync(PreferencesClass.tokenkey, token)
// 写入磁盘
store.flush()
}
// 给字段添加get方法
static getToken(content: Context, storeName: string = PreferencesClass.defaultStore) {
// 先拿到仓库名称
const store = preferences.getPreferencesSync(content, { name: storeName })
// 通过key查找vel,有可能查不到,需要给一个默认值
return store.getSync(PreferencesClass.tokenkey, '404')
}
// 删除token 不建议的做法,这样会把Key也删除,建议使用set方法覆盖一个空值
static removeToken(content: Context, storeName: string = PreferencesClass.defaultStore) {
// 先拿到仓库名称
const store = preferences.getPreferencesSync(content, { name: storeName })
// 删除
store.deleteSync(PreferencesClass.tokenkey)
// 写入磁盘
store.flush()
}
}
复制代码
onWindowStageCreate(windowStage: window.WindowStage): void {
const token = PreferencesClass.getToken(this.context)
console.log('Ability页面:',token)
if (token === '404') {
windowStage.loadContent('pages/logon');
} else {
windowStage.loadContent('pages/Index');
}
}
复制代码
import { PreferencesClass } from './PreferencesClass'
import { router } from '@kit.ArkUI'
@Entry
@Component
struct Index {
build() {
Column({ space: 20 }) {
Text('首页-登录成功')
.fontSize(50)
.fontWeight(FontWeight.Bold)
Button('退出')
.onClick(() => {
PreferencesClass.setToken(getContext(), '404')
router.back()
})
}
.height('100%')
.width('100%')
}
}
复制代码
import { PreferencesClass } from './PreferencesClass'
import { router } from '@kit.ArkUI'
@Entry
@Component
struct Logon {
@State
password: string = '123456'
build() {
Column({ space: 20 }) {
Text('登录页面')
.fontSize(50)
.fontWeight(FontWeight.Bold)
TextInput({ placeholder: '请输入用户名' })
TextInput({ placeholder: '请输入密码', text: $$this.password })
Button('登录').width('100%')
.onClick(() => {
PreferencesClass.setToken(getContext(), this.password)
router.pushUrl({
url: 'pages/Index'
})
})
}
.height('100%')
.width('100%')
}
}
复制代码
Button('查看持久化')
.onClick(()=>{
const store = preferences.getPreferencesSync(getContext(), { name:'yunOS'})
// 通过key查找vel,有可能查不到,需要给一个默认值
const dddd = store.getSync('name', '没有内容')
AlertDialog.show({message:JSON.stringify(dddd)})
})
Button('写数据进去')
.onClick(()=>{
const store = preferences.getPreferencesSync(getContext(), { name:'yunOS'})
// 再拿到key
store.putSync('name', '陈丰芸')
// 写入磁盘
store.flush()
})
复制代码
权限
网络权限
官方文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/permissions-for-all-V5
这种是体系权限,直接写就行,这个时候就可以加载网络图片了
用户权限,需要通过用户的授权的权限
// module.json5 文件
"requestPermissions": [
// 允许联网
{
"name": "ohos.permission.INTERNET"
},
// 获取地理位置
{
"name": "ohos.permission.APPROXIMATELY_LOCATION",
"reason": "$string:permission_location",
"usedScene": {
"abilities": ["EntryAbility"], // 在哪个应用开启
"when": "always" // 什么时候开启
}
}
],
复制代码
import { geoLocationManager } from '@kit.LocationKit'
@Entry
@Component
struct Index {
@State
result: geoLocationManager.Location = {} as geoLocationManager.Location
build() {
Column({ space: 20 }) {
Text('首页')
.fontSize(50)
.fontWeight(FontWeight.Bold)
Image('https://res.vmallres.com/uomcdn/CN/cms/202409/5a82eb94567d4bc2821fcc9f2991c0ec.jpg.webp')
.width('100%')
Text('获取经纬度')
.fontSize(50)
.fontWeight(FontWeight.Bold)
Button('获取').width('100%')
.onClick(async () => {
this.result = await geoLocationManager.getCurrentLocation()
})
Text('经度:' + this.result.latitude)
Text('纬度:' + this.result.longitude)
}
.height('100%')
.width('100%')
}
}
复制代码
// EntryAbility.etx 文件内容
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam):void{
// 创建程序管理控制器
const manager = abilityAccessCtrl.createAtManager()
manager.requestPermissionsFromUser(this.context,
[
"ohos.permission.APPROXIMATELY_LOCATION"
]
)
}
复制代码
除了要授权,模仿器的位置信息也需要打开
Http哀求
同步异步相关
await是等待的意思,使用这个方法需要在函数前面加async
耗时任务加await,函数前面加async
复制代码
oh-package.json5 这个文件,分为全局的和模块的,全局的就整个模块都能用,模块的就当前模块可以用
“dependencies”:{ 这内里是下载的依靠包 }
OpenHarmony三方库中央仓:https://ohpm.openharmony.cn/#/cn/home
ohpm install @ohos/axios
复制代码
import { http } from '@kit.NetworkKit'
import axios, { AxiosResponse } from '@ohos/axios'
@Entry
@Component
struct Index {
async sendHttp(){
const req = http.createHttp()
// 请求结果是字符串
const res = await req.request('https://zhousg.atomgit.net/harmonyos-next/takeaway.json')
AlertDialog.show({
message: res.result as string
})
}
async sendAxios(){
const res = await axios.get<object,AxiosResponse<object,null>,null>('https://zhousg.atomgit.net/harmonyos-next/takeaway.json')
return res
}
build() {
Column({space:20}) {
Button('处理Http请求')
.onClick(()=>{
this.sendHttp()
})
Button('处理Axios请求')
.onClick(async ()=>{ // 上面等待,底下重新赋值,也需要等待
const res = await this.sendAxios()
AlertDialog.show({
message:JSON.stringify(res.data)
})
})
}
.height('100%')
.width('100%')
}
}
复制代码
压缩图片
// 照片瘦身
async compressImage(url:string){
// 创建图片打包器
const imagePacker = image.createImagePacker()
// fd 打开文件后的唯一标识
const file = fileIo.openSync(url)
const imageSource = image.createImageSource(file.fd)
const arrayBuffer = await imagePacker.packing(imageSource,{format:'image/jpeg',quality:10})
AlertDialog.show({message:'压缩后图片大小'+formatByteLength(arrayBuffer.byteLength)})
}
复制代码
{format:'image/jpeg',quality:10}
image/jpeg // 格式的写法
quality // 0 ~ 100 值越大越,照片质量越高
复制代码
packing方法是对图片举行重新编码,得到的结果是一个文件流‘
创建图片:createAsset( )
参数1,传入什么类型的数据(比如图片:photoAccessHelper.PhotoType.IMAGE)
参数2,后缀名(jpg)
createAsset(photoAccessHelper.PhotoType.IMAGE,'jpg')
复制代码
图案锁
// 图案密码锁
// xxx.ets
import { LengthUnit, promptAction } from '@kit.ArkUI'
@Entry
@Component
struct PatternLockExample {
@State passwords: Number[] = []
@State message: string = '请输入密码!'
private patternLockController: PatternLockController = new PatternLockController()
build() {
Column() {
Text(this.message).textAlign(TextAlign.Center).margin(20).fontSize(20)
PatternLock(this.patternLockController)
.sideLength(200) // 调整图案锁大小
.circleRadius(9) // 圆点大小
.pathStrokeWidth(18) // 连线,线的宽度
.activeColor('#B0C4DE') // 点击时圆点的颜色
.selectedColor('#ff4400') // 选中后圆点的颜色
.pathColor('#90EE90') // 连线,线条的颜色
.backgroundColor('#F5F5F5')// 背景灰色
.autoReset(true) // 输入完成是否复原
.activateCircleStyle({
color: Color.Pink,
radius: { value: 16, unit: LengthUnit.VP },
enableWaveEffect: true
}) // 圆点外面发光圈的颜色
.onDotConnect((index: number) => {
promptAction.showToast({message:'点击了:'+index})
})
.onPatternComplete((input: Array<number>) => {
promptAction.showToast({message:'输入完成:'+input})
// 输入的密码长度小于5时,提示重新输入
if (input.length < 5) {
this.message = '密码长度需要大于5,请重新输入。'
return
}
// 判断密码长度是否大于0
if (this.passwords.length > 0) {
// 判断两次输入的密码是否相同,相同则提示密码设置成功,否则提示重新输入
if (this.passwords.toString() === input.toString()) {
this.passwords = input
this.message = '设置密码成功: ' + this.passwords.toString()
this.patternLockController.setChallengeResult(PatternLockChallengeResult.CORRECT)
} else {
this.message = '密码不一致,请重新输入.'
this.patternLockController.setChallengeResult(PatternLockChallengeResult.WRONG)
}
} else {
// 提示第二次输入密码
this.passwords = input
this.message = "请重新输入."
}
})
Button('重置').margin(30).onClick(() => {
// 重置密码锁
this.patternLockController.reset()
this.passwords = []
this.message = '请输入密码'
})
}.width('100%').height('100%')
}
}
复制代码
生物辨认和暗码
// 允许应用使用生物特征识别能力进行身份认证
import { userAuth } from '@kit.UserAuthenticationKit'
import { promptAction } from '@kit.ArkUI'
@Entry
@Component
struct UserAuthTestPage {
build() {
Column() {
Button('查询支持的认证能力')
.onClick(() => {
try {
userAuth.getAvailableStatus(userAuth.UserAuthType.PIN, userAuth.AuthTrustLevel.ATL1)
promptAction.showToast({ message: '有能力' })
} catch (e) {
AlertDialog.show({ message: JSON.stringify(e, null, 2) })
}
})
Button('发起认证')
.onClick(() => {
// 获取认证对象
const UserAuthInstance = userAuth.getUserAuthInstance(
{
challenge: new Uint8Array([1, 2, 33, 3]),
authType: [userAuth.UserAuthType.PIN, userAuth.UserAuthType.FINGERPRINT, userAuth.UserAuthType.FACE],
authTrustLevel: userAuth.AuthTrustLevel.ATL3
},
{ title: '请验证用户身份' }
)
// 订阅认证结果
UserAuthInstance.on('result', {
onResult(result) {
AlertDialog.show({ message: JSON.stringify(result, null, 2) })
}
})
// 发起认证
UserAuthInstance.start()
})
Button('查询支持的认证能力')
.onClick(() => {
// 鸿蒙中支持的认证类型
const userAuthTypeList: userAuth.UserAuthType[] = [
userAuth.UserAuthType.PIN,
userAuth.UserAuthType.FINGERPRINT,
userAuth.UserAuthType.FACE
]
const res = userAuthTypeList.map((item) => {
try {
userAuth.getAvailableStatus(item, userAuth.AuthTrustLevel.ATL3)
return true
} catch {
return false
}
})
const isSupport = res.some(v => v === true)
AlertDialog.show({ message: JSON.stringify(isSupport, null, 2) })
})
}
.padding(10)
.height('100%')
.width('100%')
}
}
复制代码
new Promise((resolve,reject)=>{
})
resolve 执行成功
reject 执行失败
复制代码
长期化
https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-data-relationalstore-V5
// 数据库
import { relationalStore } from '@kit.ArkData'
import { promptAction } from '@kit.ArkUI'
interface PrivacyNote{
id:number,
title:string,
content:string,
date_added:number,
}
@Entry
@Component
struct Database {
sqlCreate: string = `CREATE TABLE IF NOT EXISTS privacy_note (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
content TEXT NOT NULL,
date_added INTEGER NOT NULL
)`
store: relationalStore.RdbStore | null = null
build() {
Column({ space: 20 }) {
Button('创建数据库')
.onClick(async () => {
this.store = await relationalStore.getRdbStore(getContext(), {
name: 'cnyunos.db',
// 数据库等级,等级越低,可以共享的数据就越多
securityLevel: relationalStore.SecurityLevel.S1
})
promptAction.showToast({ message: '数据库创建成功' })
})
Button('创建数据表')
.onClick(async () => {
await this.store?.executeSql(this.sqlCreate)
promptAction.showToast({ message: '数据表创建成功' })
})
Button('查询表信息')
.onClick(async () => {
// 查表,谓词传入表名
const predicates = new relationalStore.RdbPredicates('privacy_note')
const resultSet = await this.store?.query(predicates)
promptAction.showToast({ message: '字段名称' + resultSet?.columnNames })
})
Button('删除数据库')// .enabled(false)
.onClick(() => {
relationalStore.deleteRdbStore(getContext(), 'cnyunos.db')
promptAction.showToast({ message: '数据库已经删除' })
})
}
.height('100%')
.width('100%')
.padding(10)
}
}
复制代码
this.store?.query(predicates)
用打开的数据库(数据库操作对象)文件,根据谓词查询
复制代码
向表中插入一条数据
Date.now()获取当前时间戳
复制代码
// 数据库
import { relationalStore } from '@kit.ArkData'
import { promptAction } from '@kit.ArkUI'
@Entry
@Component
struct Database {
store: relationalStore.RdbStore | null = null
@State
isStore: boolean = false
build() {
Column({ space: 20 }) {
Button('创建数据库')
.onClick(async () => {
this.store = await relationalStore.getRdbStore(getContext(), {
name: 'cnyunos.db',
// 数据库等级,等级越低,可以共享的数据就越多
securityLevel: relationalStore.SecurityLevel.S1
})
this.isStore = true
promptAction.showToast({ message: '数据库创建(打开)成功' })
})
Button('插入一条数据')
.enabled(this.isStore)
.onClick(async () => {
// 查表,谓词传入表名
const id = await this.store?.insert('privacy_note', {
id: null,
title: '测试标题',
content: '测试内容',
date_added: Date.now()
})
promptAction.showToast({ message: '新增数据成功,id:' + id })
})
}
}
}
复制代码
查询数据
Button('查询数据')
.enabled(this.isStore)
.onClick(async () => {
// 查表,谓词传入表名
const predicates = new relationalStore.RdbPredicates('privacy_note')
const resultSet = await this.store?.query(predicates)
promptAction.showToast({ message: '数据总条数:' + resultSet?.rowCount })
})
复制代码
移动指针
根据类型获取列
Button('查询数据')
.enabled(this.isStore)
.onClick(async () => {
// 查表,谓词传入表名
const predicates = new relationalStore.RdbPredicates('privacy_note')
const resultSet = await this.store?.query(predicates)
const list:PrivacyNote[] = []
// goToNextRow 移动指针到下一行,存在下一行就返回true
while(resultSet?.goToNextRow()){
// 按列提取数据
const item:PrivacyNote ={
id:resultSet.getLong(0),
title:resultSet.getString(1),
content:resultSet.getString(2),
date_added:resultSet.getLong(3),
}
// 追加到数组中
list.push(item)
}
resultSet.close() // 释放资源
promptAction.showToast({ message:JSON.stringify(list,null,2)})
})
复制代码
API11直接使用
直接可以拿到当前一行的数据
gitRow()代替下面的
id:resultSet.getLong(0),
title:resultSet.getString(1),
content:resultSet.getString(2),
date_added:resultSet.getLong(3),
复制代码
在谓词内里有排序的方式
onderByAsc('字段名') // 正序(从小到大)
onderByDesc('字段名') // 到序(从大到小)
复制代码
.in('id',[1,2,3]) // 指定哪几条
.offsetAs(1) // 偏移
.and() // &&
.limitAs(3) // 提取数值
复制代码
// 查表,谓词传入表名
const predicates = new relationalStore.RdbPredicates('privacy_note')
predicates.orderByDesc('id') // 排序倒序
predicates.offsetAs(1) // 偏移
.and() // &&
.limitAs(3) // 提取数值
复制代码
删除
Button('删除')
.enabled(this.isStore)
.onClick(async ()=>{
const predicates = new relationalStore.RdbPredicates('privacy_note')
// 不传条件,和删库没什么区别
predicates.in('id',[2,3,4])// 一次删除多条
// predicates.equalTo('id',1) // 一次删除1条
await this.store?.delete(predicates)
promptAction.showToast({ message:'删除成功'})
})
复制代码
更新
Button('修改数据')
.enabled(this.isStore)
.onClick(async ()=>{
const predicates = new relationalStore.RdbPredicates('privacy_note')
predicates.equalTo('id',1) // 不加条件,改的是全部
await this.store?.update({
title:'我是新标题',
content:'今天是1011下午'
} ,predicates)
promptAction.showToast({ message:'修改数据成功'})
})
复制代码
封装
contructor(){
this.getStoreInstance()
.then(store=>{
store.executeSql(this.sqlCreate)
})
}
复制代码
import { relationalStore, ValuesBucket } from "@kit.ArkData"
// 隐私笔记的类型
export interface PrivacyNoteDBInfo extends ValuesBucket {
id: number | null // 新增时 id 设置为 null ,可实现 id 自增
title: string
content: string
date_added: number
}
// 隐私笔记数据库封装
class PrivacyNoteDB {
// 操作数据库的实例
private store: relationalStore.RdbStore | null = null
// 数据库表名
private tableName = 'privacy_note'
// 创建数据库的语句
private sqlCreate = `CREATE TABLE IF NOT EXISTS ${this.tableName} (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
content TEXT NOT NULL,
date_added INTEGER NOT NULL
)`
// 获取数据库操作的实例
async getStoreInstance() {
// 如果数据库实例已存在,直接返回,没有才创建实例
if (this.store) { return this.store }
// 获取操作数据库的实例
const store = await relationalStore.getRdbStore(getContext(), {
name: 'yunos_data.db', // 数据库名称
securityLevel: relationalStore.SecurityLevel.S1 // 安全等级
})
// 存储起来方便下次直接获取
this.store = store
// 返回 store 实例
return this.store
}
// 类的构造器,new 的时候会自动触发
constructor() {
// 创建/打开数据库文件
this.getStoreInstance()
.then(store => {
// 执行创建语句,用于创建数据库的表
store.executeSql(this.sqlCreate)
})
}
async insert(value:PrivacyNoteDBInfo){
// 创建或打开数据库
const store= await this.getStoreInstance()
// 新增
return store.insert(this.tableName,value)
}
}
// 通过小写 p 开头的类实例操作数据库,创建数据库,建表,增、删、查、改
export const privacyNoteDB = new PrivacyNoteDB()
复制代码
调用
Button('新增').onClick(async ()=>{
const id = await privacyNoteDB.insert({
id:null,
title:'我爱',
content:'中华人民共和国',
date_added:Date.now()
})
promptAction.showToast({message:id.toString()})
})
复制代码
.enabled( ) // 其他地方也可以用
复制代码
return Promise.reject()
复制代码
华为分享(需要真机)
systemShare
utd:设置分享类型
隐私录音
AudioCapturer 更专业的音频录制开发
AVRecorder 支持跟多的编码格式
import { abilityAccessCtrl } from '@kit.AbilityKit'
import { audio } from '@kit.AudioKit';
import { promptAction } from '@kit.ArkUI';
@Entry
@Component
struct AudioCapturer {
@State isGrant: string = ''
@State isCreate: boolean = false
audioCapturer?:audio.AudioCapturer
aboutToAppear() {
this.requestPermissionsFromUser()
}
// 请求用户授权
async requestPermissionsFromUser() {
// 访问控制管理:获取访问控制模块对象
let atManager = abilityAccessCtrl.createAtManager()
let permissionRequestResult =
await atManager.requestPermissionsFromUser(getContext(), ['ohos.permission.MICROPHONE'])
AlertDialog.show({ message: JSON.stringify(permissionRequestResult, null, 2) })
this.isGrant = JSON.stringify(permissionRequestResult.dialogShownResults)
}
build() {
Column() {
Text('结果:' + this.isGrant)
Button('开始录音')
.onClick(async () => {
// 音频流信息
try {
const audioStreamInfo: audio.AudioStreamInfo = {
samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_48000, // 采样率
channels: audio.AudioChannel.CHANNEL_2, // 通道
sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE, // 采样格式
encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW // 编码格式
};
// 音频采集器信息
const audioCapturerInfo: audio.AudioCapturerInfo = {
source: audio.SourceType.SOURCE_TYPE_MIC, // 声音来源
capturerFlags: 0 // 0 代表普通音频采集器,1 代表低延时音频采集器
};
const audioCapturerOptions: audio.AudioCapturerOptions = {
streamInfo: audioStreamInfo,// 音频流信息
capturerInfo: audioCapturerInfo// 音频采集器信息
};
// AudioCapturer实例的创建
const audioCapturer = await audio.createAudioCapturer(audioCapturerOptions)
this.audioCapturer = audioCapturer
this.isCreate = true
// 订阅音频数据读入
audioCapturer.on('readData',(buffer)=>{
console.log('音频流大小',buffer.byteLength)
})
// 开始录制音频
await audioCapturer.start()
// 如果上面报错,就不会运行到这里
promptAction.showToast({ message: '调用createAudioCapturer成功.' })
} catch (error) {
promptAction.showToast({ message: `异常:${error}` })
}
})
Button('停止录音')
.enabled(this.isCreate)
.onClick(async () => {
await this.audioCapturer?.stop()
promptAction.showToast({ message: '停止成功.' })
})
Button('继续录音')
.enabled(this.isCreate)
.onClick(async () => {
await this.audioCapturer?.start()
promptAction.showToast({ message: '继续录音成功.' })
})
Button('释放资源')
.enabled(this.isCreate)
.onClick(async () => {
await this.audioCapturer?.release()
promptAction.showToast({ message: '释放资源成功.' })
})
}
.height('100%')
.width('100%')
}
}
复制代码
文件介绍
cache 缓存文件
files 持久化文件
temp 临时文件
复制代码
在持久化创建文件
const context = getContext()
// 通过应用上下文,获取到应用的files路径
const filePath = context.filesDir + '/' + 'test.wav'
fileIo.openSync(filePath,fileIo.OpenMode.CREATE | fileIo.OpenMode.READ_WRITE)
复制代码
context.filesDir // 表示files目录
'/' // 表示files目录的下一级
'test.wav' // 文件名加后缀
fileIo.OpenMode.CREATE // 文件不存在就创建
fileIo.OpenMode.READ_WRITE // 该文件的权限是可读可写
| 位运算符
复制代码
buffer 数据流
// 获取文件信息(大小,创建时间等)
const fileStat = fileIo.statSync(file.fd)
复制代码
将音频写到文件
Button('开始录音')
.enabled(!this.isCreate)
.onClick(async () => {
// 音频流信息
try {
const audioStreamInfo: audio.AudioStreamInfo = {
samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_48000, // 采样率
channels: audio.AudioChannel.CHANNEL_2, // 通道
sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE, // 采样格式
encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW // 编码格式
};
// 音频采集器信息
const audioCapturerInfo: audio.AudioCapturerInfo = {
source: audio.SourceType.SOURCE_TYPE_MIC, // 声音来源
capturerFlags: 0 // 0 代表普通音频采集器,1 代表低延时音频采集器
};
const audioCapturerOptions: audio.AudioCapturerOptions = {
streamInfo: audioStreamInfo,// 音频流信息
capturerInfo: audioCapturerInfo// 音频采集器信息
};
// AudioCapturer实例的创建
const audioCapturer = await audio.createAudioCapturer(audioCapturerOptions)
this.audioCapturer = audioCapturer
this.isCreate = true
// ----------------文件系统--------------------
const context = getContext()
// 通过应用上下文,获取到应用的files路径
const filePath = context.filesDir + '/'+ Date.now() + '.wav'
const file = fileIo.openSync(filePath,fileIo.OpenMode.CREATE | fileIo.OpenMode.READ_WRITE)
// 订阅音频数据读入
audioCapturer.on('readData',(buffer)=>{
fileIo.writeSync(file.fd,buffer)
console.log('音频流大小',buffer.byteLength)
})
// 开始录制音频
await audioCapturer.start()
// 如果上面报错,就不会运行到这里
promptAction.showToast({ message: '调用createAudioCapturer成功.' })
} catch (error) {
promptAction.showToast({ message: `异常:${error}` })
}
})
复制代码
播放音频
@State filePath:string = ''
audioRenderer?: audio.AudioRenderer
this.filePath = context.filesDir + '/'+ Date.now() + '.wav'
复制代码
Button('创建音频渲染器-播放音频')
.enabled(this.filePath!=='')
.onClick(async ()=>{
try {
const audioStreamInfo: audio.AudioStreamInfo = {
samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_48000, // 采样率
channels: audio.AudioChannel.CHANNEL_2, // 通道
sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE, // 采样格式
encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW // 编码格式
};
const audioRendererInfo: audio.AudioRendererInfo = {
usage: audio.StreamUsage.STREAM_USAGE_VOICE_COMMUNICATION,
rendererFlags: 0
};
// 音频渲染器配置
const audioRendererOptions: audio.AudioRendererOptions = {
streamInfo: audioStreamInfo,//音频流信息
rendererInfo: audioRendererInfo// 音频渲染器信息
};
// 1. 创建音频渲染器
const audioRenderer = await audio.createAudioRenderer(audioRendererOptions)
// 保存起来
this.audioRenderer = audioRenderer
// 根据路径打开文件
const file = fileIo.openSync(this.filePath)
// 获取文件信息(大小,创建时间等)
const fileIoStat =fileIo.statSync(file.fd)
// 准备一个累加值,用于自动停止渲染
let bufferSize = 0
// 2. 订阅(写入数据到音频渲染器中,就能发出声音)
audioRenderer.on('writeData',(buffer)=>{
// 读取打开的 buffer文件,写到渲染器中
fileIo.readSync(file.fd,buffer)
console.log('音频渲染器播放',buffer.byteLength)
bufferSize += buffer.byteLength
// 累加的结果是否超过文件大小
if (bufferSize >= fileIoStat.size) {
audioRenderer.stop()
}
})
// 3. 开始渲染
audioRenderer.start()
promptAction.showToast({message:'音频渲染器正常'})
} catch (error) {
promptAction.showToast({message:'音频渲染器错误:'+JSON.stringify(error)})
}
})
Button('停止渲染')
.onClick(async ()=>{
await this.audioRenderer?.stop()
promptAction.showToast({message:'停止成功'})
})
Button('销毁实例,释放资源')
.onClick(async ()=>{
await this.audioRenderer?.release()
promptAction.showToast({message:'销毁实例,释放资源成功'})
})
复制代码
录音+播放,综合
import { abilityAccessCtrl } from '@kit.AbilityKit'
import { audio } from '@kit.AudioKit';
import { promptAction } from '@kit.ArkUI';
import fileIo from '@ohos.file.fs';
@Entry
@Component
struct AudioCapturer {
@State isGrant: string = ''
@State isCreate: boolean = false
@State filePath: string = ''
audioCapturer?: audio.AudioCapturer
audioRenderer?: audio.AudioRenderer
aboutToAppear() {
this.requestPermissionsFromUser()
}
// 请求用户授权
async requestPermissionsFromUser() {
// 访问控制管理:获取访问控制模块对象
let atManager = abilityAccessCtrl.createAtManager()
let permissionRequestResult =
await atManager.requestPermissionsFromUser(getContext(), ['ohos.permission.MICROPHONE'])
AlertDialog.show({ message: JSON.stringify(permissionRequestResult, null, 2) })
this.isGrant = JSON.stringify(permissionRequestResult.dialogShownResults)
}
audioStreamInfo: audio.AudioStreamInfo = {
samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_48000, // 采样率
channels: audio.AudioChannel.CHANNEL_2, // 通道
sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE, // 采样格式
encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW // 编码格式
};
// 音频采集器信息
audioCapturerInfo: audio.AudioCapturerInfo = {
source: audio.SourceType.SOURCE_TYPE_MIC, // 声音来源
capturerFlags: 0 // 0 代表普通音频采集器,1 代表低延时音频采集器
};
audioCapturerOptions: audio.AudioCapturerOptions = {
streamInfo: this.audioStreamInfo, // 音频流信息
capturerInfo: this.audioCapturerInfo// 音频采集器信息
};
audioRendererInfo: audio.AudioRendererInfo = {
// usage: audio.StreamUsage.STREAM_USAGE_VOICE_COMMUNICATION,//用听筒播放
// usage: audio.StreamUsage.STREAM_USAGE_MOVIE,//用外放喇叭播放
usage: audio.StreamUsage.STREAM_USAGE_MUSIC, // 音乐
rendererFlags: 0
};
// 音频渲染器配置
audioRendererOptions: audio.AudioRendererOptions = {
streamInfo: this.audioStreamInfo, //音频流信息
rendererInfo: this.audioRendererInfo// 音频渲染器信息
};
build() {
Column() {
Text('结果:' + this.isGrant)
Text('音频文件的路径' + this.filePath)
Button('开始录音')
.enabled(!this.isCreate)
.onClick(async () => {
// 音频流信息
try {
// AudioCapturer实例的创建
const audioCapturer = await audio.createAudioCapturer(this.audioCapturerOptions)
this.audioCapturer = audioCapturer
this.isCreate = true
// ----------------文件系统--------------------
const context = getContext()
// 通过应用上下文,获取到应用的files路径
this.filePath = context.filesDir + '/' + Date.now() + '.wav'
const file = fileIo.openSync(this.filePath, fileIo.OpenMode.CREATE | fileIo.OpenMode.READ_WRITE)
// 订阅(读取音频采集器的数据流,写入到到开的文件中)
audioCapturer.on('readData', (buffer) => {
// 写入到打开的文件中
fileIo.writeSync(file.fd, buffer)
console.log('音频流大小', buffer.byteLength)
})
// 开始录制音频
await audioCapturer.start()
// 如果上面报错,就不会运行到这里
promptAction.showToast({ message: '调用createAudioCapturer成功.' })
} catch (error) {
promptAction.showToast({ message: `异常:${error}` })
}
})
Button('停止录音')
.enabled(this.isCreate)
.onClick(async () => {
await this.audioCapturer?.stop()
promptAction.showToast({ message: '停止成功.' })
})
Button('继续录音')
.enabled(this.isCreate)
.onClick(async () => {
await this.audioCapturer?.start()
promptAction.showToast({ message: '继续录音成功.' })
})
Button('释放资源')
.enabled(this.isCreate)
.onClick(async () => {
await this.audioCapturer?.release()
promptAction.showToast({ message: '释放资源成功.' })
})
Divider()
Button('创建音频渲染器-播放音频')
.enabled(this.filePath !== '')
.onClick(async () => {
try {
// 1. 创建音频渲染器
const audioRenderer = await audio.createAudioRenderer(this.audioRendererOptions)
// 保存起来
this.audioRenderer = audioRenderer
// 根据路径打开文件
const file = fileIo.openSync(this.filePath)
// 获取文件信息(大小,创建时间等)
const fileIoStat = fileIo.statSync(file.fd)
// 准备一个累加值,用于自动停止渲染
let bufferSize = 0
// 2. 订阅(写入数据到音频渲染器中,就能发出声音)
audioRenderer.on('writeData', (buffer) => {
// 读取打开的 buffer文件,写到渲染器中
fileIo.readSync(file.fd, buffer)
console.log('音频渲染器播放', buffer.byteLength)
bufferSize += buffer.byteLength
// 累加的结果是否超过文件大小
if (bufferSize >= fileIoStat.size) {
audioRenderer.stop()
}
})
// 3. 开始渲染
audioRenderer.start()
promptAction.showToast({ message: '音频渲染器正常' })
} catch (error) {
promptAction.showToast({ message: '音频渲染器错误:' + JSON.stringify(error) })
}
})
Button('停止渲染')
.onClick(async () => {
await this.audioRenderer?.stop()
promptAction.showToast({ message: '停止成功' })
})
Button('销毁实例,释放资源')
.onClick(async () => {
await this.audioRenderer?.release()
promptAction.showToast({ message: '销毁实例,释放资源成功' })
})
}
.height('100%')
.width('100%')
}
}
复制代码
// 释放变量,对象重新赋值为null,可以自动被 垃圾回收机制清理
this.audioCapturee = null
复制代码
文件管理(文件介绍续)
@ohos.file.fs
创建目录
const context = getContext()
// 通过应用上下文,获取到应用的files路径
const dirPath = context.filesDir + '/' + 'mydir'
if(fileIo.accessSync(dirPath)===false){ // 不存在就创建
fileIo.mkdirSync(dirPath)
}
复制代码
fileIo.accessSync( ) 检测文件或目录是否已存在
fileIo.mkdirSync( ) 创建目录
复制代码
方法的返回
demo():string{
return '*****'
}
如果这个方法前面有async就不能这样写
async demo():Promise<AudioInfo>{
await ......
return
}
复制代码
计时
// 开始录音计时
startRecordingCount() {
this.recordingTime = 0
clearInterval(this.recordingTimerId)
this.recordingTimerId = setInterval(() => {
this.recordingTime++
}, 1000)
}
// 停止录音计时
stopRecordingCount() {
clearInterval(this.recordingTimerId)
}
// 展示
Text(
dayjs(this.recordingTime*1000)
.format(this.recordingTime > 1000 * 60 * 60 ? 'HH:mm:ss' : 'mm:ss'
)
复制代码
进度条Progress
官方文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/arkts-common-components-progress-indicator-V5
// 创建一个进度总长为100,初始进度值为24的线性进度条
Progress({ value: 24, total: 100, type: ProgressType.Linear })
复制代码
介绍ProgressType类型线性样式ProgressType.Linear环形无刻度样式ProgressType.Ring环形有刻度样式ProgressType.ScaleRing圆形样式ProgressType.Eclipse胶囊样式ProgressType.Capsule
// 播放时间计时开始
startPlayingCount(duration: number) {
this.isPlaying = true
// 定义变量来保存当前的时间
this.playingTime = 0
// 定义更新间隔,单位为毫秒
const interval = 200;
clearInterval(this.playingTimerId)
this.playingTimerId = setInterval(() => {
// 累加进度条
this.playingTime += interval
if (this.playingTime > duration) {
this.stopPlayingCount()
}
}, interval)
}
复制代码
拍照
// 调用手机摄像头拍照
import { camera, cameraPicker } from '@kit.CameraKit'
@Entry
@Component
struct PickerIndex {
@State imageUrl:string = ''
build() {
Column() {
Button('拍照')
.onClick(async ()=>{
const pickerResult = await cameraPicker.pick(
getContext(),
// 是拍照还是录像
[cameraPicker.PickerMediaType.PHOTO],
{
// 默认调用的摄像头
cameraPosition:camera.CameraPosition.CAMERA_POSITION_BACK
}
)
// 如果存在图片路径,或者拍照成功
if (pickerResult.resultUri && pickerResult.resultCode === 0) {
this.imageUrl = pickerResult.resultUri
}
})
}
.height('100%')
.width('100%')
}
}
复制代码
// 隐私拍照,图片不出现在媒体库(相册)
Button('拍照')
.onClick(async ()=>{
const context = getContext()
// 文件路径
const filePath = context.filesDir + '/'+ 'test.jpg'
// 打开文件用于写入
fileIo.openSync(filePath, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE)
const pickerResult = await cameraPicker.pick(
getContext(),
// 是拍照还是录像
[cameraPicker.PickerMediaType.PHOTO],
{
// 默认调用的摄像头
cameraPosition:camera.CameraPosition.CAMERA_POSITION_BACK,
// 把 path 转换为 uri 路径
saveUri:fileUri.getUriFromPath(filePath)
})
})
复制代码
// 把 path 转换为 uri 路径
saveUri:fileUri.getUriFromPath(filePath)
// 把 uri 转换为 path
const file = fileIo.openSync(cri).path
复制代码
错误上报
import { FaultLogger } from '@kit.PerformanceAnalysisKit'
@Entry
@Component
struct ErrorPage {
build() {
Column() {
Button('查询故障日志')
.onClick(async ()=>{
const logs = await FaultLogger.query(FaultLogger.FaultType.JS_CRASH)
AlertDialog.show({message:JSON.stringify(logs,null,2)})
})
Button('抛出异常')
.onClick(()=>{
throw new Error('my error')
})
}
.height('100%')
.width('100%')
}
}
复制代码
非常捕获(防止没有捕获到的非常,让步伐闪退)
let observerId = -1
export default class EntryAbility extends UIAbility {
// 创建时
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
// 注册错误管理器
observerId = errorManager.on('error',{
async onUnhandledException(){
const logs = await FaultLogger.query(FaultLogger.FaultType.JS_CRASH)
const currentFaultLog = logs[0]
console.log('errorManager',JSON.stringify(currentFaultLog))
},
})
}
// 销毁时
onDestroy(): void {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
errorManager.off('error',observerId)
}
复制代码
报错处置惩罚
模仿器的题目,模仿器读取不到文件导致,关了,重新启动
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
欢迎光临 IT评测·应用市场-qidao123.com (https://dis.qidao123.com/)
Powered by Discuz! X3.4