簡體   English   中英

Cordova文件上傳在Windows Phone上不起作用

[英]Cordova-file-upload not working on windows phone

簡潔版本:

這段代碼很少回叫。 我在msdn之類的地方四處逛逛,找不到解決方案。 在我看來,BackgroundTransfer的BackgroundUploader的createUploadAsync的startAsync似乎啟動了,但是什么也不做。 它沒有錯誤或成功回調。

而且“很少”它實際上可以工作幾次,然后才能停止工作。 對設備進行硬重置似乎也無法解決此問題。 網絡連接通過本地局域網。 與服務器的連接穩定。 我正在Visual Studio的本地計算機上運行API的副本,請求可以成功運行。

我試圖降級到cordova 5.1.1和cordova-plugin-file-transfer 1.3.0和1.2.0,以查看它是否與我使用的版本有關。

我正在連接的服務器可以與任何其他設備一起使用。 值得注意的是,整個功能似乎都可以在Windows模擬器中使用,這讓我覺得這可能是特定的設備問題?

我可能已經割舍了自己嘗試使用Windows Phone 8.1的最新優勢

var uploader = new Windows.Networking.BackgroundTransfer.BackgroundUploader();
uploader.createUploadAsync(uri, transferParts).then(function(result) {
    var uploadOperation = upload.startAsync();
    fileTransferOps[uploadId].promise = uploadOperation;
    uploadOperation.then(successFunc, errorFunc);
}, errorCallBack);

編輯:我已經為此操作設置了一個超時,以便它在25秒后中止,但確實如此。 在所有其他(iOS / Android 4.2 / 5.x)設備上,這是即時的。 Windows Phone並不是因為某種原因而變慢,因為那里的請求時間超過60分鍾。 也許BackgroundUploader()靜默失敗...將對此進行調查。

Edit2:在此處提交了錯誤報告: https ://issues.apache.org/jira/browse/CB-10254我試圖幫助解決此問題的其他方法是禁用時間和日期同步,重新啟動設備及其像魅力一樣...。 進一步的調試表明我的所有請求都被取消或待處理。

以下是那些有興趣幫助我深入研究的人的無聊工作。

代碼示例:

$scope.album = {
uploadPhotos: function (photos) {
                var promises = [];
                for (var i = 0; i < photos.length; i++) {
                    // Windows phone doesn't work so we have to add a dirty workaround, as usual.
                    if (ionic.Platform.isWindowsPhone()) {
                        photos[i] = "cdvfile://localhost/persistent/" + decodeURIComponent(photos[i].split("/").pop());
                    }
                    var scannInvoice = parseToBool($localstorage.get("remindInvoiceScan")) ? 1 : 0;
                    promises.push($cordovaFileTransfer.upload("***HTTP Development/HTTPS Production***", photos[i], {
                        fileKey: "file",
                        fileName: photos[i].split("/").pop(),
                        httpMethod: "POST",
                        timeout: 25000,
                        chunkedMode: false,
                        contentType: "application/json; charset=utf-8",
                        // mimeType: "image/png",
                        params: { 'scannInvoice': scannInvoice },
                        headers: { 'Authorization': 'Token ' + $settings.accesstoken }
                    }).then(function (result) {
                        $fileService.setFotoUploaded(result.response);
                    }, function (err) {
                        $logService.handleException("PhotoCtrl", "Afbeelding is niet geupload", "Er is een onbekende fout opgetreden.", err, true, false, true, true);
                    }));
                } // Some $q.all call comes here that handles everything.
        }
}

在FileTransfer.js中

FileTransfer.prototype.upload = function(filePath, server, successCallback, errorCallback, options, trustAllHosts) {
argscheck.checkArgs('ssFFO*', 'FileTransfer.upload', arguments);
// check for options
var fileKey = null;
var fileName = null;
var mimeType = null;
var params = null;
var chunkedMode = true;
var headers = null;
var httpMethod = null;
var basicAuthHeader = getBasicAuthHeader(server);
if (basicAuthHeader) {
    server = server.replace(getUrlCredentials(server) + '@', '');

    options = options || {};
    options.headers = options.headers || {};
    options.headers[basicAuthHeader.name] = basicAuthHeader.value;
}

if (options) {
    fileKey = options.fileKey;
    fileName = options.fileName;
    mimeType = options.mimeType;
    headers = options.headers;
    httpMethod = options.httpMethod || "POST";
    if (httpMethod.toUpperCase() == "PUT"){
        httpMethod = "PUT";
    } else {
        httpMethod = "POST";
    }
    if (options.chunkedMode !== null || typeof options.chunkedMode != "undefined") {
        chunkedMode = options.chunkedMode;
    }
    if (options.params) {
        params = options.params;
    }
    else {
        params = {};
    }
}

if (cordova.platformId === "windowsphone") {
    headers = headers && convertHeadersToArray(headers);
    params = params && convertHeadersToArray(params);
}

var fail = errorCallback && function(e) {
    var error = new FileTransferError(e.code, e.source, e.target, e.http_status, e.body, e.exception);
    errorCallback(error);
};

var self = this;
var win = function(result) {
    if (typeof result.lengthComputable != "undefined") {
        if (self.onprogress) {
            self.onprogress(newProgressEvent(result));
        }
    } else {
        successCallback && successCallback(result);
    }
};
exec(win, fail, 'FileTransfer', 'upload', [filePath, server, fileKey, fileName, mimeType, params, trustAllHosts, chunkedMode, headers, this._id, httpMethod]);
};

並在FileTransferProxy.js中

module.exports = {

/*
    exec(win, fail, 'FileTransfer', 'upload', 
    [filePath, server, fileKey, fileName, mimeType, params, trustAllHosts, chunkedMode, headers, this._id, httpMethod]);
*/
upload:function(successCallback, errorCallback, options) {
    var filePath = options[0];
    var server = options[1];
    var fileKey = options[2] || 'source';
    var fileName = options[3];
    var mimeType = options[4];
    var params = options[5];
    // var trustAllHosts = options[6]; // todo
    // var chunkedMode = options[7]; // todo 
    var headers = options[8] || {};
    var uploadId = options[9];

    if (!filePath || (typeof filePath !== 'string')) {
        errorCallback(new FTErr(FTErr.FILE_NOT_FOUND_ERR,null,server));
        return;
    }

    if (filePath.substr(0, 8) === "file:///") {
        filePath = appData.localFolder.path + filePath.substr(8).split("/").join("\\");
    } else if (filePath.indexOf('ms-appdata:///') === 0) {
        // Handle 'ms-appdata' scheme
        filePath = filePath.replace('ms-appdata:///local', appData.localFolder.path)
                           .replace('ms-appdata:///temp', appData.temporaryFolder.path);
    }
    // normalize path separators
    filePath = cordovaPathToNative(filePath);

    // Create internal download operation object
    fileTransferOps[uploadId] = new FileTransferOperation(FileTransferOperation.PENDING, null);

    Windows.Storage.StorageFile.getFileFromPathAsync(filePath)
    .then(function (storageFile) {

        if(!fileName) {
            fileName = storageFile.name;
        }
        if(!mimeType) {
            // use the actual content type of the file, probably this should be the default way.
            // other platforms probably can't look this up.
            mimeType = storageFile.contentType;
        }

        // check if download isn't already cancelled
        var uploadOp = fileTransferOps[uploadId];
        if (uploadOp && uploadOp.state === FileTransferOperation.CANCELLED) {
            // Here we should call errorCB with ABORT_ERR error
            errorCallback(new FTErr(FTErr.ABORT_ERR, nativePathToCordova(filePath), server));
            return;
        }

        // setting request headers for uploader
        var uploader = new Windows.Networking.BackgroundTransfer.BackgroundUploader();
        for (var header in headers) {
            if (headers.hasOwnProperty(header)) {
                uploader.setRequestHeader(header, headers[header]);
            }
        }

        // adding params supplied to request payload
        var transferParts = [];
        for (var key in params) {
            if (params.hasOwnProperty(key)) {
                var contentPart = new Windows.Networking.BackgroundTransfer.BackgroundTransferContentPart();
                contentPart.setHeader("Content-Disposition", "form-data; name=\"" + key + "\"");
                contentPart.setText(params[key]);
                transferParts.push(contentPart);
            }
        }

        // Adding file to upload to request payload
        var fileToUploadPart = new Windows.Networking.BackgroundTransfer.BackgroundTransferContentPart(fileKey, fileName);
        fileToUploadPart.setFile(storageFile);
        transferParts.push(fileToUploadPart);

        // create download object. This will throw an exception if URL is malformed
        var uri = new Windows.Foundation.Uri(server);
        try {
            uploader.createUploadAsync(uri, transferParts).then(
                function (upload) {
                    // update internal TransferOperation object with newly created promise
                    var uploadOperation = upload.startAsync();
                    fileTransferOps[uploadId].promise = uploadOperation;

                    uploadOperation.then(
                        function (result) {
                            // Update TransferOperation object with new state, delete promise property
                            // since it is not actual anymore
                            var currentUploadOp = fileTransferOps[uploadId];
                            if (currentUploadOp) {
                                currentUploadOp.state = FileTransferOperation.DONE;
                                currentUploadOp.promise = null;
                            }

                            var response = result.getResponseInformation();
                            var ftResult = new FileUploadResult(result.progress.bytesSent, response.statusCode, '');

                            // if server's response doesn't contain any data, then resolve operation now
                            if (result.progress.bytesReceived === 0) {
                                successCallback(ftResult);
                                return;
                            }

                            // otherwise create a data reader, attached to response stream to get server's response
                            var reader = new Windows.Storage.Streams.DataReader(result.getResultStreamAt(0));
                            reader.loadAsync(result.progress.bytesReceived).then(function (size) {
                                ftResult.response = reader.readString(size);
                                successCallback(ftResult);
                                reader.close();
                            });
                        },
                        function (error) {
                            var source = nativePathToCordova(filePath);

                            // Handle download error here.
                            // Wrap this routines into promise due to some async methods
                            var getTransferError = new WinJS.Promise(function(resolve) {
                                if (error.message === 'Canceled') {
                                    // If download was cancelled, message property will be specified
                                    resolve(new FTErr(FTErr.ABORT_ERR, source, server, null, null, error));
                                } else {
                                    // in the other way, try to get response property
                                    var response = upload.getResponseInformation();
                                    if (!response) {
                                        resolve(new FTErr(FTErr.CONNECTION_ERR, source, server));
                                    } else {
                                        var reader = new Windows.Storage.Streams.DataReader(upload.getResultStreamAt(0));
                                        reader.loadAsync(upload.progress.bytesReceived).then(function (size) {
                                            var responseText = reader.readString(size);
                                            resolve(new FTErr(FTErr.FILE_NOT_FOUND_ERR, source, server, response.statusCode, responseText, error));
                                            reader.close();
                                        });
                                    }
                                }
                            });

                            // Update TransferOperation object with new state, delete promise property
                            // since it is not actual anymore
                            var currentUploadOp = fileTransferOps[uploadId];
                            if (currentUploadOp) {
                                currentUploadOp.state = FileTransferOperation.CANCELLED;
                                currentUploadOp.promise = null;
                            }

                            // Cleanup, remove incompleted file
                            getTransferError.then(function(transferError) {
                                storageFile.deleteAsync().then(function() {
                                    errorCallback(transferError);
                                });
                            });
                        },
                        function (evt) {
                            var progressEvent = new ProgressEvent('progress', {
                                loaded: evt.progress.bytesSent,
                                total: evt.progress.totalBytesToSend,
                                target: evt.resultFile
                            });
                            progressEvent.lengthComputable = true;
                            successCallback(progressEvent, { keepCallback: true });
                        }
                    );
                },
                function (err) {
                    var errorObj = new FTErr(FTErr.INVALID_URL_ERR);
                    errorObj.exception = err;
                    errorCallback(errorObj);
                }
            );
        } catch (e) {
            errorCallback(new FTErr(FTErr.INVALID_URL_ERR));
        }
    }, function(err) {
        errorCallback(new FTErr(FTErr.FILE_NOT_FOUND_ERR, server, server, null, null, err));
    });
},
};

我的設置信息:

Windows Phone 8.1, Nokia Lumia 520

在我的taco.json中

{
  "cordova-cli": "5.4.1"
}

使用Windows Platform 4.2.0

當前添加的插件

  <vs:plugin name="cordova-plugin-device" version="1.1.0" />
  <vs:plugin name="cordova-plugin-whitelist" version="1.2.0" />
  <vs:plugin name="cordova-plugin-file" version="3.0.0" />
  <vs:plugin name="cordova-plugin-network-information" version="1.1.0" />
  <vs:plugin name="cordova-plugin-inappbrowser" version="1.1.1" />
  <vs:plugin name="cordova-plugin-statusbar" version="2.0.0" />
  <vs:plugin name="cordova-plugin-camera" version="2.0.0" src="https://github.com/apache/cordova-plugin-camera" />
  <vs:plugin name="cordova-plugin-file-transfer" version="1.4.0" />

最后在我的index.html中

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
    <meta http-equiv="Content-Security-Policy" content="default-src * 'self' cdvfile://*; data: gap: https://ssl.gstatic.com; style-src 'unsafe-inline' 'self' cdvfile://*; script-src 'self' 'unsafe-eval' cdvfile://*">
    <meta name="format-detection" content="telephone=no">
    <title></title>
    <!-- stylesheets -->
    <link href="css/ionic.min.css" rel="stylesheet" />
    <link href="css/ionic-overrides.css" rel="stylesheet" />
    <link href="css/angular-chart.css" rel="stylesheet" />
    <link href="css/isteven-omni-bar.css" rel="stylesheet" />
    <!-- library -->
    <script src="cordova.js"></script>
    <script src="scripts/platformOverrides.js"></script>
    <script src="scripts/ionic.bundle.custom.js"></script>
    <script src="scripts/ng-cordova.js"></script>
    <!-- application -->
    <script src="js/app.js"></script>
    <script src="js/services/localstorage.js"></script>
    <script src="js/services/settings.js"></script>
    <!-- config -->
    <script src="js/config/ionicPlatform.js"></script>
    <script src="js/config/compileProvider.js"></script>
    <script src="js/config/stateProvider.js"></script>
    <script src="js/config/formatFilters.js"></script>
    <script src="js/config/directives.js"></script>
    <!-- controllers -->
    <script src="js/controllers/LoginController.js"></script>
    <script src="js/controllers/AppController.js"></script>
    <script src="js/controllers/DashboardController.js"></script>
    <script src="js/controllers/PhotoController.js"></script>
    <script src="js/controllers/AdministrationController.js"></script>
    <script src="js/controllers/MutationController.js"></script>
    <!-- services -->
    <script src="js/services/administrationService.js"></script>
    <script src="js/services/fileService.js"></script>
    <script src="js/services/logService.js"></script>
    <!-- scripts -->
    <script src="scripts/helpers.js"></script>
    <script src="scripts/chart/highcharts.js"></script>
    <script src="scripts/chart/highcharts-ng.js"></script>
    <script src="scripts/isteven-omni-bar.js"></script>
</head>

發生此問題后,我通過執行以下步驟設法始終如一地解決了該問題。

  1. 卸載開發應用程序。
  2. 在您的項目中,刪除文件傳輸插件。
  3. 添加文件傳輸插件的1.4.1-dev版本(包括對請求標頭的修復)。
  4. 從您的項目文件夾中刪除bld,build,platforms,plugins文件夾(它們將使用用於Visual Studio的Apache Cordova工具進行重建。)
  5. 硬重置Windows Phone。
  6. 重建。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM