HarmonyOs
1.沙箱文件操作
应用沙箱是一种一啊全防护为目的的隔离机制,避免数据受到恶意路径穿越访问。在这种沙箱的保护机制下 应用可见的目录范围即为“应用沙箱目录”
沙箱路径在
1.获取沙箱目录
getContext().cacheDir
getContext().fileDir
getContext().tempDir
2.文件操作
harmonyos提供文件操作的api,相当于nodejs的中的fs操作
值得注意的是:在api9中 使用fs在当前的API11heAPI12中 官方又提供了fileIO的基础方法,用法和fs基本一致
open 打开文件
close 关闭文件
write 写入文件
copy 复制文件
unlink 删除文件
mkdir 创建文件夹
上述方法均支持promise并提供有对应的同步方法
想要操作一个文件 ,首先要打开一个文件,读取一个文件的buffer或者fd,通过fd进行文件的buffer进行相应的操作
下载图片方法他是一个promise函数 返回的是一个下载任务的状态 有三种状态 一是进度 二是失败 三是下载完成
let task = await request.downloadFile(getContext(), {url: this.url,filePath: filePath})// 下载进度task.on('progress', () => {})// 下载失败task.on('fail', () => {})// 下载成功task.on('complete', () => {this.filePath = filePathpromptAction.showToast({message: '下载成功了'})})
3.需求 实现一个图片 点击按钮下载到沙箱 并读取沙箱里的图片进行展示
import { request } from '@kit.BasicServicesKit';
import { promptAction } from '@kit.ArkUI';@Entry
@Component
struct DownLoadPage {@State url: string = 'https://c-ssl.dtstatic.com/uploads/item/202003/05/20200305161241_dfqmr.thumb.1000_0.jpg';@State filePath: string = ''async downLoad() {let filePath = getContext().filesDir + '/' + Date.now() + '.jpg'let task = await request.downloadFile(getContext(), {url: this.url,filePath: filePath})// 下载进度task.on('progress', () => {})// 下载失败task.on('fail', () => {})// 下载成功task.on('complete', () => {this.filePath = filePathpromptAction.showToast({message: '下载成功了'})})}build() {Column({ space: 20 }) {Image(this.url).width('100%').height(200)Button('下载图片').onClick(() => {this.downLoad()})Image('file://' + this.filePath).width(200).height(200)}.height('100%').width('100%')}
}
读取沙箱内的文件要是用文件读取 即 “file://”
2.混合开发中的热更新操作
需求 将这个压缩包下载到沙箱 如果已经有了就再给它换个名字 路径放在下方:https://gitee.com/shuiruohanyu/toutiao_net/blob/master/resources/toutiao.zip
重点代码:
let fileName = 'toutiao.zip'let filePath = getContext().filesDir + '/' + fileNameif (fileIo.listFileSync(getContext().filesDir).includes(fileName)) {fileIo.renameSync(filePath, getContext().filesDir + '/' + 'toutiao.bak.zip')}let task = await request.downloadFile(getContext(), {url: 'https://gitee.com/shuiruohanyu/toutiao_net/blob/master/resources/toutiao.zip',filePath: filePath})task.on('progress', (currentValue, totel) => {this.currentValue = currentValuethis.totel = totel})task.on('complete', () => {this.showMask = falsepromptAction.showToast({message: '下载成功了'})})
全部代码
import { request } from '@kit.BasicServicesKit';
import { fileIo } from '@kit.CoreFileKit';
import { promptAction } from '@kit.ArkUI';@Entry
@Component
struct DownLoadHotPage {@State message: string = '沙箱热更新';@State showMask: boolean = false;@State currentValue: number = 0@State totel: number = 0@BuildermaskPopup() {Column() {Progress({value: this.currentValue,total: this.totel})}.width('100%').height('100%').justifyContent(FlexAlign.Center).backgroundColor('rgba(0,0,0,0.5)')}async downLoad() {this.showMask = truelet fileName = 'toutiao.zip'let filePath = getContext().filesDir + '/' + fileNameif (fileIo.listFileSync(getContext().filesDir).includes(fileName)) {fileIo.renameSync(filePath, getContext().filesDir + '/' + 'toutiao.bak.zip')}let task = await request.downloadFile(getContext(), {url: 'https://gitee.com/shuiruohanyu/toutiao_net/blob/master/resources/toutiao.zip',filePath: filePath})task.on('progress', (currentValue, totel) => {this.currentValue = currentValuethis.totel = totel})task.on('complete', () => {this.showMask = falsepromptAction.showToast({message: '下载成功了'})})}build() {Column() {Button('热更新').onClick(() => {this.downLoad()})}.height('100%').width('100%').bindContentCover($$this.showMask, this.maskPopup, {modalTransition: ModalTransition.NONE})}
}
看下下载下来的zip吧
解压操作
async decompressFile() {try {await zlib.decompressFile(getContext().filesDir + '/' + 'toutiao.zip', getContext().filesDir)} catch (errData) {console.log(errData, 'dsjfjksdf')}}
解压成功后 我们就可以在Web组件中使用解压后的html
然后加载页面
controller: webview.WebviewController = new webview.WebviewController()build() {Column() {// Web的默认是禁止了浏览器的页面的存储化Web({src: 'file://' + getContext().tempDir + '/toutiao/index.html',controller: this.controller}).domStorageAccess(true) //解决页面中不能存储的问题.width('100%').height('100%')}}
3. 原生能力
1.音视频播放Vedio
@Entry
@Component
struct VideoPage {@State message: string = '音视频';build() {Column() {// 网络路径Video({src: 'https://vdept3.bdstatic.com/mda-qhia4gdeicc3c2gc/sc/cae_h264/1724119722028125307/mda-qhia4gdeicc3c2gc.mp4?v_from_s=hkapp-haokan-hbe&auth_key=1725010231-0-0-8fc29a5968bade17df3138163bbd3e5d&bcevod_channel=searchbox_feed&cr=2&cd=0&pd=1&pt=3&logid=1831750927&vid=10380342571472452940&klogid=1831750927&abtest=87345_2'}).width('100%').height(200)// 资源路径Video({src: $rawfile('video.mp4')}).width('100%').height(200)// 普通文件夹路径路径Video({src: '/assets/video1.mp4'}).width('100%').height(200)}.height('100%').width('100%')}
}
控制它的播放或暂停能力、重点代码截图
@Entry
@Component
struct VideoPage {@State message: string = '音视频';controller: VideoController = new VideoController();build() {Column() {// 资源路径Video({src: $rawfile('video.mp4'),controller: this.controller}).width('100%').height(200)Button('播放').onClick((event: ClickEvent) => {this.controller.start()})Button('暂停').onClick((event: ClickEvent) => {this.controller.pause()})}.height('100%').width('100%')}
}
设置不显示下边的那个控制器
.controls(false)
Video({src: $rawfile('video.mp4'),controller: this.controller}).controls(false).width('100%').height(200)
设置它的倍速
@Entry
@Component
struct VideoPage {@State message: string = '音视频';controller: VideoController = new VideoController();@State speed: number = 0.7build() {Column() {// 资源路径Video({src: $rawfile('video.mp4'),controller: this.controller,currentProgressRate: this.speed}).controls(false).width('100%').height(200)Button('播放').onClick((event: ClickEvent) => {this.controller.start()})Button('暂停').onClick((event: ClickEvent) => {this.controller.pause()})Slider({value: $$this.speed,min: 0.75,max: 2,step: 0.25})}.height('100%').width('100%')}
}
重点代码截图
2.抖音小案例
3.canvas
- ArkUI里边的画布和前端的Canvas的用法一致
- 使用方法:
- 放置Canvas组件 -给宽和高
- 初始化画笔对象CanvasRenderingContext2D,将画笔作为构造参数传递给Canvas组件
- 可以在Canvas的onReady事件中进行动态绘制
- 绘制方法官方文档
@Entry
@Component
struct CanvasPage {@State message: string = 'Hello World';myPen: CanvasRenderingContext2D = new CanvasRenderingContext2D()build() {Column() {Canvas(this.myPen).width('100%').height(300).backgroundColor(Color.Gray)Button('画线').onClick(() => {this.myPen.lineWidth = 4 //绘画的线的宽度this.myPen.strokeStyle = 'red' //绘画的线的颜色this.myPen.beginPath()//开始绘画this.myPen.moveTo(20, 20) //开始绘画的坐标this.myPen.lineTo(340, 280) //结束绘画的坐标this.myPen.stroke() //绘画出来this.myPen.closePath()//结束绘画})}.justifyContent(FlexAlign.Center).height('100%').width('100%')}
}
点击按钮 出现这么个效果
3.写个签字版吧
@Entry
@Component
struct SignaturePage {@State message: string = '签字版';myPen: CanvasRenderingContext2D = new CanvasRenderingContext2D()Cwidth: number = 0Cheight: number = 0build() {Column() {Button('清除签字板').onClick(() => {this.myPen.clearRect(0, 0, this.Cwidth, this.Cheight)})Canvas(this.myPen).width('100%').height(300).backgroundColor(Color.Gray).onAreaChange((oldArea, newArea) => {this.Cwidth = newArea.width as numberthis.Cheight = newArea.height as number}).onReady(() => {this.myPen.lineWidth = 2this.myPen.strokeStyle = 'red'}).onTouch((event: TouchEvent) => {// console.log(event.tiltX.toString())if (event.type == TouchType.Down) {console.log('按下了')this.myPen.beginPath()this.myPen.moveTo(event.touches[0].x, event.touches[0].y)} else if (event.type == TouchType.Move) {console.log('移动了')this.myPen.lineTo(event.touches[0].x, event.touches[0].y)this.myPen.stroke()} else if (event.type == TouchType.Up) {console.log('松开了')this.myPen.closePath()}})}.height('100%').width('100%').justifyContent(FlexAlign.Center)}
}