UNPKG

react-native-ohos-docviewer

Version:

这是一款基于React Native HarmonyOS端文件文档查看器(pdf、png、jpg、xml、xls、doc、ppt、xlsx、docx、pptx 等)开源插件

267 lines (248 loc) 9.34 kB
import { TurboModule, TurboModuleContext } from '@rnoh/react-native-openharmony/ts'; import util from '@ohos.util' import { fileIo, fileUri } from '@kit.CoreFileKit'; import { getMimeType } from '../mime' import request from '@ohos.request'; import { Mime } from '../../utils/Mime'; import { filePreview } from '@kit.PreviewKit'; import { BusinessError } from '@kit.BasicServicesKit'; import { Want, wantConstant } from '@kit.AbilityKit'; import { http } from "@kit.NetworkKit"; interface FileInfo { url?: string, fileName?: string, fileType?: string, cache?: boolean, base64?: string } export class DocViewerTurboModule extends TurboModule { tempDir: string constructor(ctx: TurboModuleContext) { super(ctx) this.ctx = ctx this.createTempDir() } createTempDir() { const context = this.ctx.uiAbilityContext let filesDir = context.filesDir + `/docViewerTemp` this.tempDir = filesDir fileIo.mkdir(filesDir) } async saveBase64(base64: string, filePath: string) { const baseHelper = new util.Base64Helper() const buf = baseHelper.decodeSync(base64).buffer as ArrayBuffer const file = await fileIo.open(filePath, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE) await fileIo.write(file.fd, buf) fileIo.close(file) } async openDocb64(fileParams: FileInfo[], callback: Function) { console.log(`openDocb64 start params:${JSON.stringify(fileParams)}`) const { base64, fileName, fileType, cache } = fileParams[0] if (base64 && fileName && fileType) { try { const filePath = this.getFilePath(fileName, fileType) if (cache) { this.useCache(fileType, '', fileName, callback, async () => { await this.saveBase64(base64, filePath) this.shareFile(filePath, fileType, callback) }) } else { await this.saveBase64(base64, filePath) this.shareFile(filePath, fileType, callback) } } catch (e) { callback(`openDocb64 execute failed`) } } else { callback(`Requires parameters: base64, fileName, fileType`) } } async openDocBinaryinUrl(fileParams: FileInfo[], callback: Function) { let httpRequest = http.createHttp(); const { url, fileName, fileType, cache } = fileParams[0] const filePath = this.getFilePath(fileName, fileType, url); const chunks: ArrayBuffer[] = []; // 存储所有数据块 try { if (url && fileName && fileType) { if (cache) { this.useCache(fileType, url, fileName, callback) } else { httpRequest.requestInStream(url, { expectDataType: http.HttpDataType.ARRAY_BUFFER, method: http.RequestMethod.GET, // 可选,默认为http.RequestMethod.GET。 connectTimeout: 60000, readTimeout: 60000 }) httpRequest.on('dataReceiveProgress',(data)=>{ const progress = data.receiveSize * 100 /data.totalSize; if(progress<100){ this.ctx?.rnInstance?.emitDeviceEvent('RNDownloaderProgress',{progress}); } }) httpRequest.on('dataReceive',(buffer)=>{ chunks.push(buffer); }) httpRequest.on('dataEnd',()=>{ this.ctx?.rnInstance?.emitDeviceEvent('RNDownloaderProgress',{progress:100}); // 合并所有ArrayBuffer const totalLength = chunks.reduce((len, chunk) => len + chunk.byteLength, 0); const mergedBuffer = new Uint8Array(totalLength); let offset = 0; chunks.forEach(chunk => { mergedBuffer.set(new Uint8Array(chunk), offset); offset += chunk.byteLength; }); // 一次性写入完整数据 const tempFile = fileIo.openSync(filePath, 0o102); fileIo.writeSync(tempFile.fd, mergedBuffer.buffer); fileIo.closeSync(tempFile.fd); this.shareFile(filePath, fileType, callback); }) } } else { callback(`Requires parameters: url,fileName,fileType`) } } catch (e) { callback(`${JSON.stringify(e)}`) } } async openDoc(fileParams: FileInfo[], callback: Function) { const { url, fileName, fileType, cache } = fileParams[0] try { if (url) { if (cache) { this.useCache(fileType, url, fileName, callback) } else { await this.download(url, fileType, fileName, callback) } } else { callback(`Requires parameters: url`) } } catch (e) { callback(`${JSON.stringify(e)}`) } } getFilePath(fileName: string, fileType: string, url?: string) { let filedDir = this.tempDir if (fileName) { return `${filedDir}/${fileName}${fileType ? '.' + fileType : ''}` } if (url) { const urlSplit = url?.split('/') const name = urlSplit[urlSplit.length - 1] const filePath = filedDir + `/${name?.includes('.') ? name : (fileType ? name + `.${fileType}` : '')}` return filePath } return '' } async useCache(fileType: string, url: string, fileName: string, callback: Function, notExistsFn?: Function) { const filePath = this.getFilePath(fileName, fileType, url) const isExists = await fileIo.access(filePath) if (isExists) { this.shareFile(filePath, fileType, callback) } else { if (notExistsFn) { notExistsFn() } else { this.download(url, fileType, fileName, callback) } } } async removeFile(filePath: string) { try { const isExists = await fileIo.access(filePath) if (isExists) { await fileIo.unlink(filePath) } } catch (err) { } } async download(url: string, fileType: string, fileName: string, callback: Function) { const filePath = this.getFilePath(fileName, fileType, url) const context = this.ctx.uiAbilityContext try { request.downloadFile(context, { url, filePath }).then(downloadTask => { downloadTask.on('complete', () => { this.shareFile(filePath, fileType, callback) }) downloadTask.on("progress", (receivedSize: number, totalSize: number) => { this.ctx?.rnInstance?.emitDeviceEvent("RNDownloaderProgress", { progress: (receivedSize/totalSize) *100 }) }) downloadTask.on('fail', (err) => { this.removeFile(filePath) callback(`download fail:${err}`) }) }).catch(err => { callback(`Invoke catch downloadTask failed:${JSON.stringify(err)}`) }) } catch (err) { if (err.code === 13400002) { this.shareFile(filePath, fileType, callback) } else { callback(`download fail:${JSON.stringify(err)}`) } } } shareFile(filePath: string, fileType: string, callback: Function) { const uri = fileUri.getUriFromPath(filePath) this.start(uri, fileType, callback) } generatePreviewInfo(uri: string): filePreview.PreviewInfo { let fileName = Mime.getFileUri(uri).name; let fileExtention = Mime.getFileExtention(fileName); let mimeType = getMimeType(fileExtention); let previewInfo: filePreview.PreviewInfo = { title: fileName, uri: uri, mimeType: mimeType }; return previewInfo; } start(uri: string, fileType: string, callback: Function) { // const context = this.ctx.uiAbilityContext // let fileName = Mime.getFileUri(uri).name; // let mimeType = getMimeType(Mime.getFileExtention(fileName)); // let want: Want = { // flags: // (wantConstant.Flags.FLAG_AUTH_WRITE_URI_PERMISSION | wantConstant.Flags.FLAG_AUTH_READ_URI_PERMISSION) , // action:'ohos.want.action.viewData', // uri: uri, // type: mimeType // } // context.startAbility(want, (err, data) => { // if (err.code !== 0) { // console.log(`share file err:${JSON.stringify(err)}`) // callback(`want startAbility err:${JSON.stringify(err)}`) // } else { // callback('', uri) // } // }) filePreview.canPreview(this.ctx.uiAbilityContext, uri).then((result) => { filePreview.openPreview(this.ctx.uiAbilityContext, this.generatePreviewInfo(uri)).then(() => { callback('', uri) }).catch((err: BusinessError) => { callback(`Failed to open preview, err.code = ${err.code}, err.message = ${err.message}`) }); }).catch((err: BusinessError) => { callback(`Failed to obtain the result of whether it can be previewed, err.code = ${err.code}, err.message = ${err.message}`); }); } onSharePreview(uri: string, write: boolean = true): Promise<void> { const context = this.ctx.uiAbilityContext let fileName = Mime.getFileUri(uri).name; let mimeType = getMimeType(Mime.getFileExtention(fileName)); let want: Want = { // 配置被分享文件的读写权限,例如对被分享应用进行读写授权 flags: write ? (wantConstant.Flags.FLAG_AUTH_WRITE_URI_PERMISSION | wantConstant.Flags.FLAG_AUTH_READ_URI_PERMISSION) : wantConstant.Flags.FLAG_AUTH_READ_URI_PERMISSION, action: 'ohos.want.action.sendData', //配置分享应用的隐式拉起规则 uri: uri, type: mimeType } return context.startAbility(want); } }