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 = filePath
promptAction.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 = filePath
promptAction.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 + '/' + fileName
if (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 = currentValue
this.totel = totel
})
task.on('complete', () => {
this.showMask = false
promptAction.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
@Builder
maskPopup() {
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 = true
let fileName = 'toutiao.zip'
let filePath = getContext().filesDir + '/' + fileName
if (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 = currentValue
this.totel = totel
})
task.on('complete', () => {
this.showMask = false
promptAction.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.7
build() {
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 = 0
Cheight: number = 0
build() {
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 number
this.Cheight = newArea.height as number
}
)
.onReady(() => {
this.myPen.lineWidth = 2
this.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)
}
}