UNPKG

imobile_for_reactnative

Version:

iMobile for ReactNative,是SuperMap iMobile推出的一款基于React-Native框架的移动应用开发工具。基于该开发工具,用户可以使用JavaScript开发语言,开发出在Android和IOS操作系统下运行的原生移动GIS应用,入门门槛低,一次开发,处处运行。

583 lines (490 loc) 21.6 kB
/** * React Native FS * @flow */ 'use strict'; // This file supports both iOS and Android let RNFSManager = require('react-native').NativeModules.RNFSManager; let NativeAppEventEmitter = require('react-native').NativeAppEventEmitter; // iOS let DeviceEventEmitter = require('react-native').DeviceEventEmitter; // Android let base64 = require('base-64'); let utf8 = require('utf8'); let isIOS = require('react-native').Platform.OS === 'ios'; let RNFSFileTypeRegular = RNFSManager.RNFSFileTypeRegular; let RNFSFileTypeDirectory = RNFSManager.RNFSFileTypeDirectory; let jobId = 0; let getJobId = () => { jobId += 1; return jobId; }; let normalizeFilePath = (path: string) => (path.startsWith('file://') ? path.slice(7) : path); export type MkdirOptions = { NSURLIsExcludedFromBackupKey?: boolean; // iOS only NSFileProtectionKey?: string; // IOS only }; export type FileOptions = { NSFileProtectionKey?: string; // IOS only }; export type ReadDirItem = { ctime?: Date; // The creation date of the file (iOS only) mtime?: Date; // The last modified date of the file name: string; // The name of the item path: string; // The absolute path to the item size: string; // Size in bytes isFile: () => boolean; // Is the file just a file? isDirectory: () => boolean; // Is the file a directory? }; export type StatResult = { name?: string; // The name of the item TODO: why is this not documented? path: string; // The absolute path to the item size: string; // Size in bytes mode: number; // UNIX file mode ctime: number; // Created date mtime: number; // Last modified date originalFilepath: string; // In case of content uri this is the pointed file path, otherwise is the same as path isFile: () => boolean; // Is the file just a file? isDirectory: () => boolean; // Is the file a directory? }; export type Headers = { [name: string]: string }; export type Fields = { [name: string]: string }; export type DownloadFileOptions = { fromUrl: string; // URL to download file from toFile: string; // Local filesystem path to save the file to headers?: Headers; // An object of headers to be passed to the server background?: boolean; // Continue the download in the background after the app terminates (iOS only) discretionary?: boolean; // Allow the OS to control the timing and speed of the download to improve perceived performance (iOS only) cacheable?: boolean; // Whether the download can be stored in the shared NSURLCache (iOS only) progressDivider?: number; begin?: (res: DownloadBeginCallbackResult) => void; progress?: (res: DownloadProgressCallbackResult) => void; resumable?: () => void; // only supported on iOS yet connectionTimeout?: number; // only supported on Android yet readTimeout?: number; // supported on Android and iOS }; export type DownloadBeginCallbackResult = { jobId: number; // The download job ID, required if one wishes to cancel the download. See `stopDownload`. statusCode: number; // The HTTP status code contentLength: number; // The total size in bytes of the download resource headers: Headers; // The HTTP response headers from the server }; export type DownloadProgressCallbackResult = { jobId: number; // The download job ID, required if one wishes to cancel the download. See `stopDownload`. contentLength: number; // The total size in bytes of the download resource bytesWritten: number; // The number of bytes written to the file so far }; export type DownloadResult = { jobId: number; // The download job ID, required if one wishes to cancel the download. See `stopDownload`. statusCode: number; // The HTTP status code bytesWritten: number; // The number of bytes written to the file }; export type UploadFileOptions = { toUrl: string; // URL to upload file to files: UploadFileItem[]; // An array of objects with the file information to be uploaded. headers?: Headers; // An object of headers to be passed to the server fields?: Fields; // An object of fields to be passed to the server method?: string; // Default is 'POST', supports 'POST' and 'PUT' beginCallback?: (res: UploadBeginCallbackResult) => void; // deprecated progressCallback?: (res: UploadProgressCallbackResult) => void; // deprecated begin?: (res: UploadBeginCallbackResult) => void; progress?: (res: UploadProgressCallbackResult) => void; }; export type UploadFileItem = { name: string; // Name of the file, if not defined then filename is used filename: string; // Name of file filepath: string; // Path to file filetype: string; // The mimetype of the file to be uploaded, if not defined it will get mimetype from `filepath` extension }; export type UploadBeginCallbackResult = { jobId: number; // The upload job ID, required if one wishes to cancel the upload. See `stopUpload`. }; export type UploadProgressCallbackResult = { jobId: number; // The upload job ID, required if one wishes to cancel the upload. See `stopUpload`. totalBytesExpectedToSend: number; // The total number of bytes that will be sent to the server totalBytesSent: number; // The number of bytes sent to the server }; export type UploadResult = { jobId: number; // The upload job ID, required if one wishes to cancel the upload. See `stopUpload`. statusCode: number; // The HTTP status code headers: Headers; // The HTTP response headers from the server body: string; // The HTTP response body }; export type FSInfoResult = { totalSpace: number; // The total amount of storage space on the device (in bytes). freeSpace: number; // The amount of available storage space on the device (in bytes). }; /** * Generic function used by readFile and readFileAssets */ function readFileGeneric(filepath: string, encodingOrOptions?: string, command: Function) { let options = { encoding: 'utf8' }; if (encodingOrOptions) { if (typeof encodingOrOptions === 'string') { options.encoding = encodingOrOptions; } else if (typeof encodingOrOptions === 'object') { options = encodingOrOptions; } } return command(normalizeFilePath(filepath)).then((b64: string) => { let contents; if (options.encoding === 'utf8') { contents = utf8.decode(base64.decode(b64)); } else if (options.encoding === 'ascii') { contents = base64.decode(b64); } else if (options.encoding === 'base64') { contents = b64; } else { throw new Error('Invalid encoding type "' + String(options.encoding) + '"'); } return contents; }); } /** * Generic function used by readDir and readDirAssets */ function readDirGeneric(dirpath: string, command: Function) { return command(normalizeFilePath(dirpath)).then(files => { return files.map(file => ({ ctime: file.ctime && new Date(file.ctime * 1000) || null, mtime: file.mtime && new Date(file.mtime * 1000) || null, name: file.name, path: file.path, size: file.size, isFile: () => file.type === RNFSFileTypeRegular, isDirectory: () => file.type === RNFSFileTypeDirectory, })); }); } export function mkdir(filepath: string, options: MkdirOptions = {}): Promise<void> { return RNFSManager.mkdir(normalizeFilePath(filepath), options).then(() => void 0); } export function moveFile(filepath: string, destPath: string, options: FileOptions = {}): Promise<void> { return RNFSManager.moveFile(normalizeFilePath(filepath), normalizeFilePath(destPath), options).then(() => void 0); } export function copyFile(filepath: string, destPath: string, options: FileOptions = {}): Promise<void> { return RNFSManager.copyFile(normalizeFilePath(filepath), normalizeFilePath(destPath), options).then(() => void 0); } export function pathForBundle(bundleNamed: string): Promise<string> { return RNFSManager.pathForBundle(bundleNamed); } export function pathForGroup(groupName: string): Promise<string> { return RNFSManager.pathForGroup(groupName); } export function getFSInfo(): Promise<FSInfoResult> { return RNFSManager.getFSInfo(); } export function getAllExternalFilesDirs(): Promise<string> { return RNFSManager.getAllExternalFilesDirs(); } export function unlink(filepath: string): Promise<void> { return RNFSManager.unlink(normalizeFilePath(filepath)).then(() => void 0); } export function exists(filepath: string): Promise<boolean> { return RNFSManager.exists(normalizeFilePath(filepath)); } export function stopDownload(jobId: number): void { RNFSManager.stopDownload(jobId); } export function resumeDownload(jobId: number): void { RNFSManager.resumeDownload(jobId); } export function isResumable(jobId: number): Promise<boolean> { return RNFSManager.isResumable(jobId); } export function stopUpload(jobId: number): void { RNFSManager.stopUpload(jobId); } export function completeHandlerIOS(jobId: number): void { return RNFSManager.completeHandlerIOS(jobId); } export function readDir(dirpath: string): Promise<ReadDirItem[]> { return readDirGeneric(dirpath, RNFSManager.readDir); } // Android-only export function readDirAssets(dirpath: string): Promise<ReadDirItem[]> { if (!RNFSManager.readDirAssets) { throw new Error('readDirAssets is not available on this platform'); } return readDirGeneric(dirpath, RNFSManager.readDirAssets); } // Android-only export function existsAssets(filepath: string) { if (!RNFSManager.existsAssets) { throw new Error('existsAssets is not available on this platform'); } return RNFSManager.existsAssets(filepath); } // Node style version (lowercase d). Returns just the names export function readdir(dirpath: string): Promise<string[]> { return readDir(normalizeFilePath(dirpath)).then(files => { return files.map(file => file.name); }); } // setReadable for Android export function setReadable(filepath: string, readable: boolean, ownerOnly: boolean): Promise<boolean> { return RNFSManager.setReadable(filepath, readable, ownerOnly).then((result) => { return result; }) } export function stat(filepath: string): Promise<StatResult> { return RNFSManager.stat(normalizeFilePath(filepath)).then((result) => { return { 'path': filepath, 'ctime': new Date(result.ctime * 1000), 'mtime': new Date(result.mtime * 1000), 'size': result.size, 'mode': result.mode, 'originalFilepath': result.originalFilepath, isFile: () => result.type === RNFSFileTypeRegular, isDirectory: () => result.type === RNFSFileTypeDirectory, }; }); } export function readFile(filepath: string, encodingOrOptions?: any): Promise<string> { return readFileGeneric(filepath, encodingOrOptions, RNFSManager.readFile); } export function read(filepath: string, length: number = 0, position: number = 0, encodingOrOptions?: any): Promise<string> { let options = { encoding: 'utf8' }; if (encodingOrOptions) { if (typeof encodingOrOptions === 'string') { options.encoding = encodingOrOptions; } else if (typeof encodingOrOptions === 'object') { options = encodingOrOptions; } } return RNFSManager.read(normalizeFilePath(filepath), length, position).then((b64) => { let contents; if (options.encoding === 'utf8') { contents = utf8.decode(base64.decode(b64)); } else if (options.encoding === 'ascii') { contents = base64.decode(b64); } else if (options.encoding === 'base64') { contents = b64; } else { throw new Error('Invalid encoding type "' + String(options.encoding) + '"'); } return contents; }); } // Android only export function readFileAssets(filepath: string, encodingOrOptions?: any): Promise<string> { if (!RNFSManager.readFileAssets) { throw new Error('readFileAssets is not available on this platform'); } return readFileGeneric(filepath, encodingOrOptions, RNFSManager.readFileAssets); } export function hash(filepath: string, algorithm: string): Promise<string> { return RNFSManager.hash(normalizeFilePath(filepath), algorithm); } // Android only export function copyFileAssets(filepath: string, destPath: string) { if (!RNFSManager.copyFileAssets) { throw new Error('copyFileAssets is not available on this platform'); } return RNFSManager.copyFileAssets(normalizeFilePath(filepath), normalizeFilePath(destPath)).then(() => void 0); } // iOS only // Copies fotos from asset-library (camera-roll) to a specific location // with a given width or height // @see: https://developer.apple.com/reference/photos/phimagemanager/1616964-requestimageforasset export function copyAssetsFileIOS(imageUri: string, destPath: string, width: number, height: number, scale: number = 1.0, compression: number = 1.0, resizeMode: string = 'contain'): Promise<string> { return RNFSManager.copyAssetsFileIOS(imageUri, destPath, width, height, scale, compression, resizeMode); } // iOS only // Copies fotos from asset-library (camera-roll) to a specific location // with a given width or height // @see: https://developer.apple.com/reference/photos/phimagemanager/1616964-requestimageforasset export function copyAssetsVideoIOS(imageUri: string, destPath: string): Promise<string> { return RNFSManager.copyAssetsVideoIOS(imageUri, destPath); } export function writeFile(filepath: string, contents: string, encodingOrOptions?: any): Promise<void> { let b64; let options = { encoding: 'utf8' }; if (encodingOrOptions) { if (typeof encodingOrOptions === 'string') { options.encoding = encodingOrOptions; } else if (typeof encodingOrOptions === 'object') { options = { ...options, ...encodingOrOptions }; } } if (options.encoding === 'utf8') { b64 = base64.encode(utf8.encode(contents)); } else if (options.encoding === 'ascii') { b64 = base64.encode(contents); } else if (options.encoding === 'base64') { b64 = contents; } else { throw new Error('Invalid encoding type "' + options.encoding + '"'); } return RNFSManager.writeFile(normalizeFilePath(filepath), b64, options).then(() => void 0); } export function appendFile(filepath: string, contents: string, encodingOrOptions?: any): Promise<void> { let b64; let options = { encoding: 'utf8' }; if (encodingOrOptions) { if (typeof encodingOrOptions === 'string') { options.encoding = encodingOrOptions; } else if (typeof encodingOrOptions === 'object') { options = encodingOrOptions; } } if (options.encoding === 'utf8') { b64 = base64.encode(utf8.encode(contents)); } else if (options.encoding === 'ascii') { b64 = base64.encode(contents); } else if (options.encoding === 'base64') { b64 = contents; } else { throw new Error('Invalid encoding type "' + options.encoding + '"'); } return RNFSManager.appendFile(normalizeFilePath(filepath), b64); } export function write(filepath: string, contents: string, position?: number, encodingOrOptions?: any): Promise<void> { let b64; let options = { encoding: 'utf8' }; if (encodingOrOptions) { if (typeof encodingOrOptions === 'string') { options.encoding = encodingOrOptions; } else if (typeof encodingOrOptions === 'object') { options = encodingOrOptions; } } if (options.encoding === 'utf8') { b64 = base64.encode(utf8.encode(contents)); } else if (options.encoding === 'ascii') { b64 = base64.encode(contents); } else if (options.encoding === 'base64') { b64 = contents; } else { throw new Error('Invalid encoding type "' + options.encoding + '"'); } if (position === undefined) { position = -1; } return RNFSManager.write(normalizeFilePath(filepath), b64, position).then(() => void 0); } export function downloadFile(options: DownloadFileOptions): { jobId: number, promise: Promise<DownloadResult> } { if (typeof options !== 'object') throw new Error('downloadFile: Invalid value for argument `options`'); if (typeof options.fromUrl !== 'string') throw new Error('downloadFile: Invalid value for property `fromUrl`'); if (typeof options.toFile !== 'string') throw new Error('downloadFile: Invalid value for property `toFile`'); if (options.headers && typeof options.headers !== 'object') throw new Error('downloadFile: Invalid value for property `headers`'); if (options.background && typeof options.background !== 'boolean') throw new Error('downloadFile: Invalid value for property `background`'); if (options.progressDivider && typeof options.progressDivider !== 'number') throw new Error('downloadFile: Invalid value for property `progressDivider`'); if (options.readTimeout && typeof options.readTimeout !== 'number') throw new Error('downloadFile: Invalid value for property `readTimeout`'); if (options.connectionTimeout && typeof options.connectionTimeout !== 'number') throw new Error('downloadFile: Invalid value for property `connectionTimeout`'); let jobId = getJobId(); let subscriptions = []; if (options.begin) { subscriptions.push(NativeAppEventEmitter.addListener('DownloadBegin-' + jobId, options.begin)); } if (options.progress) { subscriptions.push(NativeAppEventEmitter.addListener('DownloadProgress-' + jobId, options.progress)); } if (options.resumable) { subscriptions.push(NativeAppEventEmitter.addListener('DownloadResumable-' + jobId, options.resumable)); } let bridgeOptions = { jobId: jobId, fromUrl: options.fromUrl, toFile: normalizeFilePath(options.toFile), headers: options.headers || {}, background: !!options.background, progressDivider: options.progressDivider || 0, readTimeout: options.readTimeout || 15000, connectionTimeout: options.connectionTimeout || 5000 }; return { jobId, promise: RNFSManager.downloadFile(bridgeOptions).then(res => { subscriptions.forEach(sub => sub.remove()); return res; }) .catch(e => { return Promise.reject(e); }) }; } export function uploadFiles(options: UploadFileOptions): { jobId: number, promise: Promise<UploadResult> } { if (!RNFSManager.uploadFiles) { return { jobId: -1, promise: Promise.reject(new Error('`uploadFiles` is unsupported on this platform')) }; } let jobId = getJobId(); let subscriptions = []; if (typeof options !== 'object') throw new Error('uploadFiles: Invalid value for argument `options`'); if (typeof options.toUrl !== 'string') throw new Error('uploadFiles: Invalid value for property `toUrl`'); if (!Array.isArray(options.files)) throw new Error('uploadFiles: Invalid value for property `files`'); if (options.headers && typeof options.headers !== 'object') throw new Error('uploadFiles: Invalid value for property `headers`'); if (options.fields && typeof options.fields !== 'object') throw new Error('uploadFiles: Invalid value for property `fields`'); if (options.method && typeof options.method !== 'string') throw new Error('uploadFiles: Invalid value for property `method`'); if (options.begin) { subscriptions.push(NativeAppEventEmitter.addListener('UploadBegin-' + jobId, options.begin)); } if (options.beginCallback && options.beginCallback instanceof Function) { // Deprecated subscriptions.push(NativeAppEventEmitter.addListener('UploadBegin-' + jobId, options.beginCallback)); } if (options.progress) { subscriptions.push(NativeAppEventEmitter.addListener('UploadProgress-' + jobId, options.progress)); } if (options.progressCallback && options.progressCallback instanceof Function) { // Deprecated subscriptions.push(NativeAppEventEmitter.addListener('UploadProgress-' + jobId, options.progressCallback)); } let bridgeOptions = { jobId: jobId, toUrl: options.toUrl, files: options.files, headers: options.headers || {}, fields: options.fields || {}, method: options.method || 'POST' }; return { jobId, promise: RNFSManager.uploadFiles(bridgeOptions).then(res => { subscriptions.forEach(sub => sub.remove()); return res; }) }; } export function touch(filepath: string, mtime?: Date, ctime?: Date): Promise<void> { if (ctime && !(ctime instanceof Date)) throw new Error('touch: Invalid value for argument `ctime`'); if (mtime && !(mtime instanceof Date)) throw new Error('touch: Invalid value for argument `mtime`'); let ctimeTime = 0; if (isIOS) { ctimeTime = ctime && ctime.getTime(); } return RNFSManager.touch( normalizeFilePath(filepath), mtime && mtime.getTime(), ctimeTime ); } export function scanFile(path: string): Promise<ReadDirItem[]> { return RNFSManager.scanFile(path); } export const MainBundlePath = RNFSManager.RNFSMainBundlePath export const CachesDirectoryPath = RNFSManager.RNFSCachesDirectoryPath export const ExternalCachesDirectoryPath = RNFSManager.RNFSExternalCachesDirectoryPath export const DocumentDirectoryPath = RNFSManager.RNFSDocumentDirectoryPath export const ExternalDirectoryPath = RNFSManager.RNFSExternalDirectoryPath export const ExternalStorageDirectoryPath = RNFSManager.RNFSExternalStorageDirectoryPath export const TemporaryDirectoryPath = RNFSManager.RNFSTemporaryDirectoryPath export const LibraryDirectoryPath = RNFSManager.RNFSLibraryDirectoryPath export const PicturesDirectoryPath = RNFSManager.RNFSPicturesDirectoryPath export const FileProtectionKeys = RNFSManager.RNFSFileProtectionKeys