在HarmonyOS应用开发中,开发者经常需要实现各种文件的预览功能,包括:
如何利用HarmonyOS提供的filePreview服务统一实现这些不同来源文件的预览,是开发者面临的一个常见需求。
HarmonyOS提供了Preview Kit(文件预览服务)框架,这是一个用于文件预览的统一接口服务。
previewLocalFile() {
try {
const filePath = `${this.context.filesDir}/sample.pdf`;
// 检查文件是否存在
const isExist = fs.accessSync(filePath);
if (!isExist) {
console.error('本地文件不存在,请确保文件已放置到应用目录');
return;
}
// 构建PreviewInfo
let uri = fileUri.getUriFromPath(filePath);
let fileInfo: filePreview.PreviewInfo = {
title: 'sample.pdf',
uri: uri,
mimeType: 'application/pdf',
};
// 打开文件预览
filePreview.openPreview(this.context, fileInfo).then(() => {
console.info('Succeeded in opening preview');
}).catch((err: BusinessError) => {
console.error(`Failed to open preview, err.code = ${err.code}, err.message = ${err.message}`);
});
} catch (error) {
console.error(`预览rawfile文件失败: ${JSON.stringify(error)}`);
}
} previewRawFile() {
try {
// 预览rawfile文件,需要将文件复制到沙箱目录
let filePath = `${this.context.filesDir}/sample.pdf`;
const resourceMgr = this.context.resourceManager;
resourceMgr.getRawFileContent('sample.pdf', (err, value) => {
let myBuffer: ArrayBufferLike = value.buffer;
// 创建sample.pdf沙箱路径,并写入数据
let file = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
fs.writeSync(file.fd, myBuffer);
fs.close(file);
});
let uri = fileUri.getUriFromPath(filePath);
let fileInfo: filePreview.PreviewInfo = {
title: 'sample.pdf',
uri: uri,
mimeType: 'application/pdf',
};
// 打开文件预览
filePreview.openPreview(this.context, fileInfo).then(() => {
console.info('Succeeded in opening preview');
}).catch((err: BusinessError) => {
console.error(`Failed to open preview, err.code = ${err.code}, err.message = ${err.message}`);
});
} catch (error) {
console.error(`预览rawfile文件失败: ${JSON.stringify(error)}`);
}
} previewNetworkFile() {
// url需替换为实际可用的pdf url
const url = 'https://****.com/test.pdf';
let filePath = `${this.context.filesDir}/sample.pdf`;
try {
// 网络文件下载到本地
let res = fs.accessSync(filePath);
if (res) {
// 本地文件存在,则直接调用预览方法
console.info('file exists and ViewFile');
let uri = fileUri.getUriFromPath(filePath);
let fileInfo: filePreview.PreviewInfo = {
title: 'sample.pdf',
uri: uri,
mimeType: 'application/pdf',
};
// 打开文件预览
filePreview.openPreview(this.context, fileInfo).then(() => {
console.info('Succeeded in opening preview');
}).catch((err: BusinessError) => {
console.error(`Failed to open preview, err.code = ${err.code}, err.message = ${err.message}`);
});
} else {
// 文件下载到本地
request.downloadFile(this.context, {
url: url,
filePath: filePath
}).then((downloadTask: request.DownloadTask) => {
// 下载完成回调
downloadTask.on('complete', () => {
console.info('download complete');
let uri = fileUri.getUriFromPath(filePath);
let fileInfo: filePreview.PreviewInfo = {
title: 'sample.pdf',
uri: uri,
mimeType: 'application/pdf',
};
// 打开文件预览
filePreview.openPreview(this.context, fileInfo).then(() => {
console.info('Succeeded in opening preview');
}).catch((err: BusinessError) => {
console.error(`Failed to open preview, err.code = ${err.code}, err.message = ${err.message}`);
});
});
}).catch((err: BusinessError) => {
console.error(`Invoke downloadTask failed, code is ${err.code}, message is ${err.message}`);
});
}
} catch (error) {
let err: BusinessError = error as BusinessError;
console.error(`Invoke downloadFile failed, code is ${err.code}, message is ${err.message}`);
}
} import { fileUri, fileIo as fs } from '@kit.CoreFileKit';
import { filePreview } from '@kit.PreviewKit';
import { BusinessError, request } from '@kit.BasicServicesKit';
import { common } from '@kit.AbilityKit';
@Entry
@Component
struct Index {
context = this.getUIContext().getHostContext() as common.UIAbilityContext;
// Start solution1
previewLocalFile() {
try {
const filePath = `${this.context.filesDir}/sample.pdf`;
// 检查文件是否存在
const isExist = fs.accessSync(filePath);
if (!isExist) {
console.error('本地文件不存在,请确保文件已放置到应用目录');
return;
}
// 构建PreviewInfo
let uri = fileUri.getUriFromPath(filePath);
let fileInfo: filePreview.PreviewInfo = {
title: 'sample.pdf',
uri: uri,
mimeType: 'application/pdf',
};
// 打开文件预览
filePreview.openPreview(this.context, fileInfo).then(() => {
console.info('Succeeded in opening preview');
}).catch((err: BusinessError) => {
console.error(`Failed to open preview, err.code = ${err.code}, err.message = ${err.message}`);
});
} catch (error) {
console.error(`预览rawfile文件失败: ${JSON.stringify(error)}`);
}
}
// End solution1
// Start solution2
previewRawFile() {
try {
// 预览rawfile文件,需要将文件复制到沙箱目录
let filePath = `${this.context.filesDir}/sample.pdf`;
const resourceMgr = this.context.resourceManager;
resourceMgr.getRawFileContent('sample.pdf', (err, value) => {
let myBuffer: ArrayBufferLike = value.buffer;
// 创建sample.pdf沙箱路径,并写入数据
let file = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
fs.writeSync(file.fd, myBuffer);
fs.close(file);
});
let uri = fileUri.getUriFromPath(filePath);
let fileInfo: filePreview.PreviewInfo = {
title: 'sample.pdf',
uri: uri,
mimeType: 'application/pdf',
};
// 打开文件预览
filePreview.openPreview(this.context, fileInfo).then(() => {
console.info('Succeeded in opening preview');
}).catch((err: BusinessError) => {
console.error(`Failed to open preview, err.code = ${err.code}, err.message = ${err.message}`);
});
} catch (error) {
console.error(`预览rawfile文件失败: ${JSON.stringify(error)}`);
}
}
// End solution2
// Start solution3
previewNetworkFile() {
// url需替换为实际可用的pdf url
const url = 'https://****.com/test.pdf';
let filePath = `${this.context.filesDir}/sample.pdf`;
try {
// 网络文件下载到本地
let res = fs.accessSync(filePath);
if (res) {
// 本地文件存在,则直接调用预览方法
console.info('file exists and ViewFile');
let uri = fileUri.getUriFromPath(filePath);
let fileInfo: filePreview.PreviewInfo = {
title: 'sample.pdf',
uri: uri,
mimeType: 'application/pdf',
};
// 打开文件预览
filePreview.openPreview(this.context, fileInfo).then(() => {
console.info('Succeeded in opening preview');
}).catch((err: BusinessError) => {
console.error(`Failed to open preview, err.code = ${err.code}, err.message = ${err.message}`);
});
} else {
// 文件下载到本地
request.downloadFile(this.context, {
url: url,
filePath: filePath
}).then((downloadTask: request.DownloadTask) => {
// 下载完成回调
downloadTask.on('complete', () => {
console.info('download complete');
let uri = fileUri.getUriFromPath(filePath);
let fileInfo: filePreview.PreviewInfo = {
title: 'sample.pdf',
uri: uri,
mimeType: 'application/pdf',
};
// 打开文件预览
filePreview.openPreview(this.context, fileInfo).then(() => {
console.info('Succeeded in opening preview');
}).catch((err: BusinessError) => {
console.error(`Failed to open preview, err.code = ${err.code}, err.message = ${err.message}`);
});
});
}).catch((err: BusinessError) => {
console.error(`Invoke downloadTask failed, code is ${err.code}, message is ${err.message}`);
});
}
} catch (error) {
let err: BusinessError = error as BusinessError;
console.error(`Invoke downloadFile failed, code is ${err.code}, message is ${err.message}`);
}
}
// End solution3
build() {
Column() {
Button('预览rawfile pdf文件')
.onClick(() => {
this.previewRawFile();
})
.width('70%')
.margin({ bottom: 20 });
Button('预览沙箱pdf文件')
.onClick(() => {
this.previewLocalFile();
})
.width('70%')
.margin({ bottom: 20 });
Button('预览网络pdf文件')
.onClick(() => {
this.previewNetworkFile();
})
.width('70%')
.margin({ bottom: 20 });
}
.height('100%')
.width('100%')
.alignItems(HorizontalAlign.Center)
.justifyContent(FlexAlign.Center);
}
} Q:模拟器是否支持Preview Kit文件预览?
A:当前Preview Kit支持模拟器开发,但与真机存在部分能力差异,详情请见模拟器与真机的差异列表。
Q:预览mp4文件时,通过uniformTypeDescriptor.getTypeDescriptor获取的mimeType为video/mp4,video/mp4v,能否直接作为PreviewInfo的mimeType参数?
A:预览mp4文件时,mimeType参数需要为video/mp4,见文件预览支持的文件类型。
Q:使用filePreview预览文件时,能否关闭分享入口、关闭"使用WPS打开"入口以及添加水印,防止文件被上传或泄露到其他地方?
A:当前Preview Kit暂不支持安全定制能力,包括关闭分享入口、屏蔽其他应用打开入口、添加水印等安全预览能力。如需实现应用内安全预览,建议使用三方SDK(如WPS等)提供应用内打开能力。
Preview Kit(文件预览服务)为文件预览提供了统一的解决方案:
实际开发中应根据具体场景选择合适的预览方式,并处理好错误情况和用户权限问题。对于敏感文件,还应该增加额外的安全验证机制。