【问题标题】:Ionic 3 Post Camera Image to API With cordova-plugin-fileIonic 3 使用 cordova-plugin-file 将相机图像发布到 API
【发布时间】:2018-08-25 17:19:07
【问题描述】:

我已成功使用 cordova-plugin-file-transfer 将图像文件从设备相机发布到 API,例如fileTransfer.upload(fileUrl, url, options).

但是,cordova-plugin-file-transfer 现在已被弃用: “随着 XMLHttpRequest 中引入的新功能,不再需要这个插件。从这个插件迁移到使用 XMLHttpRequest 的新功能,在这篇 Cordova 博客文章中进行了解释。” https://github.com/apache/cordova-plugin-file-transfer

建议的新方法是使用 cordova-plugin-file 和 XMLHttpRequest。 https://cordova.apache.org/blog/2017/10/18/from-filetransfer-to-xhr2.html

window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fs) {
    console.log('file system open: ' + fs.name);
    fs.root.getFile('bot.png', { create: true, exclusive: false }, function (fileEntry) {
        fileEntry.file(function (file) {
            var reader = new FileReader();
            reader.onloadend = function() {
                // Create a blob based on the FileReader "result", which we asked to be retrieved as an ArrayBuffer
                var blob = new Blob([new Uint8Array(this.result)], { type: "image/png" });
                var oReq = new XMLHttpRequest();
                oReq.open("POST", "http://mysweeturl.com/upload_handler", true);
                oReq.onload = function (oEvent) {
                    // all done!
                };
                // Pass the blob in to XHR's send method
                oReq.send(blob);
            };
            // Read the file as an ArrayBuffer
            reader.readAsArrayBuffer(file);
        }, function (err) { console.error('error getting fileentry file!' + err); });
    }, function (err) { console.error('error getting file! ' + err); });
}, function (err) { console.error('error getting persistent fs! ' + err); });

在上面的示例中,我们可以将 XMLHttpRequest 替换为 Angular 5 HttpClient,例如

this.http.post(path, body, options);

cordova-plugin-camera 文档建议使用 DestinationType = FILE_URI 或 NATIVE_URI,它们都返回类似于以下内容的路径/文件:content://media/external/images/media/1249。他们特别警告不要返回 base64 编码的字符串。

“返回 base64 编码字符串。DATA_URL 可能会占用大量内存并导致应用程序崩溃或内存不足错误。如果可能,请使用 FILE_URI 或 NATIVE_URI” https://github.com/apache/cordova-plugin-camera#module_Camera.DestinationType

似乎这里新的/正确的方法是使用cordova-plugin-file 来获取文件,将此文件转换为blob,然后将其发布到API。

首先,我想我需要使用cordova-plugin-file中的resolveLocalFilesystemUrl转换相机localFile:https://ionicframework.com/docs/native/file/

this.file.resolveLocalFilesystemUrl(localFile).then((entry) => {
    console.log(entry.fullPath);
});

Android 示例:

localFile: content://media/external/images/media/1249
resolvedLocalFile: content://media/external/images/media/1827

但是,我无法使用带cordova-plugin-file 的resolvedLocalFile 来获取文件并转换为blob(然后最终发布到API)。

这是正确的方法吗?如果是这样,这是一个有效的代码示例。如果没有,正确的方法是什么?请注意,我已经看到发布 base64 编码字符串的示例,但 cordova-plugin-camera 明确警告这一点。

【问题讨论】:

    标签: ionic3


    【解决方案1】:

    以下是基于该方法的工作存根:使用 cordova-plugin-file 获取文件,将文件转换为 blob,将 blob 发布到 API。这篇文章对创建这个存根也很有帮助:https://golb.hplar.ch/2017/02/Uploading-pictures-from-Ionic-2-to-Spring-Boot.html

    主程序:

    this.cameraProvider.getPicture()
        .flatMap(imageData => {
            return this.cameraProvider.imageDataToBlob(imageData);
        })
        .flatMap(blob => {
            return this.workerProvider.updateImage(blob);
        }).subscribe();
    

    使用 cordova-plugin-camera 获取文件:

    public getPicture(): Observable<any> {
    
        const options: CameraOptions = {
            destinationType: this.camera.DestinationType.FILE_URI,
            encodingType: this.camera.EncodingType.JPEG,
            mediaType: this.camera.MediaType.PICTURE,
            sourceType: this.camera.PictureSourceType.PHOTOLIBRARY
        }
    
        return Observable.fromPromise(
            this.platform.ready().then(() => {
                if (this.platform.is('cordova')) {
                    return this.camera.getPicture(options).then((imageData: any) => {
    
                        // Android DestinationType.FILE_URI returns a local image url in this form: content://media/external/images/media/1249
                        // iOS DestinationType.FILE_URI returns a local image url in this form: file:///var/mobile/Containers/Data/Application/25A3F622-38DB-4701-AB20-90AAE9AC02C8/tmp/cdv_photo_002.jpg
                        return imageData;
    
                    }).catch((error) => {
                        // Handle error.
                    })
                }
                else {
                    return Observable.of(null);
                }
            })
        )
    }
    

    将文件转换为 blob:

    public imageDataToBlob(imageData): Observable<any> {
    
        return Observable.fromPromise(this.file.resolveLocalFilesystemUrl(imageData))
            .flatMap((fileEntry: FileEntry) => { // Cast entry to fileEntry.
                return this.fileEntryToObservable(fileEntry)
            })
            .flatMap((file) => {
                return this.fileReaderToObservable(file)
            });
    }
    
    public fileEntryToObservable(fileEntry: any): Observable<any> {
    
        return Observable.create(observer => {
            // Success.
            fileEntry.file(function(file) {
                observer.next(file);
            },
            // Error.
            function (error) {
                observer.error(error)
            })
        });
    }
    
    public fileReaderToObservable(file: any): Observable<any> {
    
        const fileReader = new FileReader();
        fileReader.readAsArrayBuffer(file);
    
        return Observable.create(observer => {
            // Success.
            fileReader.onload = ev => {
                let formData = new FormData();
                let imgBlob = new Blob([fileReader.result], { type: file.type });
                observer.next(imgBlob);
            }
            // Error.
            fileReader.onerror = error => observer.error(error);
        });
    }
    

    将 blob 发布到 API:

    // Do NOT add Content-Type multipart/form-data to header.
    let headers = new HttpHeaders()
    
    const formData = new FormData();
    formData.append('file', blob, 'image');
    
    let options = { headers: headers };
    return this.http.post(url, formData, options);
    

    【讨论】:

      猜你喜欢
      • 2020-05-06
      • 1970-01-01
      • 1970-01-01
      • 2015-09-24
      • 1970-01-01
      • 1970-01-01
      • 2023-03-11
      • 1970-01-01
      • 2018-07-24
      相关资源
      最近更新 更多