Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.

Commit 1c661bc

Browse files
ermikbytenikalexandergoncharov-zz
authored
Switch to cordova-plugin-advanced-http for update downloads (#513)
* Update plugin.xml * patch XCode 10 usage with `build.json` flags - add build.json to pass additional flags to cordova - use build.json to pass `UseModernBuildSystem=0` avoiding build failure * switch from plugin-file-transfer to to raw XHR * rollback config.xml tweak * remove plugin-file-transfer from project * Eliminated file-transfer from workaround hook * fix ProgressEvent typings, TS defs, commit JS * add cordova plugin file as an explicit dependency * CORS: drop xhr in favor of advanced-http plugin * fix: dependency minor version * switch from promises to callbacks * add dependency on plugin-zip * fix typo * update advanced-http dependency * use plugin-advanced-http for all http requests * fix body serialization * added getDataDirectory call to ensure path - as discussed in #513, with move to advanced-http, the update payload began to fail - The call to getDataDirectory triggers path creation, if it doesn't exist yet Co-authored-by: Alexander Goncharov <[email protected]> Co-authored-by: David Pfeffer <[email protected]> Co-authored-by: unknown <[email protected]> Co-authored-by: Alexander Goncharov <[email protected]>
1 parent 15fe2c8 commit 1c661bc

12 files changed

+256
-133
lines changed

bin/www/fileUtil.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ var FileUtil = (function () {
228228
fileEntry.file(function (file) {
229229
var fileReader = new FileReader();
230230
fileReader.onloadend = function (ev) {
231-
callback(null, ev.target.result);
231+
callback(null, fileReader.result);
232232
};
233233
fileReader.onerror = function () {
234234
callback(new Error("Could not get file. Error: " + fileReader.error.message), null);

bin/www/httpRequester.js

+53-32
Original file line numberDiff line numberDiff line change
@@ -8,58 +8,79 @@
88

99

1010
"use strict";
11+
var __extends = (this && this.__extends) || (function () {
12+
var extendStatics = function (d, b) {
13+
extendStatics = Object.setPrototypeOf ||
14+
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
15+
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
16+
return extendStatics(d, b);
17+
};
18+
return function (d, b) {
19+
extendStatics(d, b);
20+
function __() { this.constructor = d; }
21+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
22+
};
23+
})();
24+
var CodePushUtil = require("./codePushUtil");
1125
var HttpRequester = (function () {
1226
function HttpRequester(contentType) {
13-
this.contentType = contentType;
27+
cordova.plugin.http.setHeader("X-CodePush-Plugin-Name", "cordova-plugin-code-push");
28+
cordova.plugin.http.setHeader("X-CodePush-Plugin-Version", cordova.require("cordova/plugin_list").metadata["cordova-plugin-code-push"]);
29+
cordova.plugin.http.setHeader("X-CodePush-SDK-Version", cordova.require("cordova/plugin_list").metadata["code-push"]);
30+
if (contentType) {
31+
cordova.plugin.http.setHeader("Content-Type", contentType);
32+
}
1433
}
1534
HttpRequester.prototype.request = function (verb, url, callbackOrRequestBody, callback) {
16-
var requestBody;
1735
var requestCallback = callback;
36+
var options = HttpRequester.getInitialOptionsForVerb(verb);
37+
if (options instanceof Error) {
38+
CodePushUtil.logError("Could not make the HTTP request", options);
39+
requestCallback && requestCallback(options, undefined);
40+
return;
41+
}
1842
if (!requestCallback && typeof callbackOrRequestBody === "function") {
1943
requestCallback = callbackOrRequestBody;
2044
}
2145
if (typeof callbackOrRequestBody === "string") {
22-
requestBody = callbackOrRequestBody;
23-
}
24-
var xhr = new XMLHttpRequest();
25-
var methodName = this.getHttpMethodName(verb);
26-
xhr.onreadystatechange = function () {
27-
if (xhr.readyState === 4) {
28-
var response = { statusCode: xhr.status, body: xhr.responseText };
29-
requestCallback && requestCallback(null, response);
30-
}
31-
};
32-
xhr.open(methodName, url, true);
33-
if (this.contentType) {
34-
xhr.setRequestHeader("Content-Type", this.contentType);
46+
options.serializer = "utf8";
47+
options.data = callbackOrRequestBody;
3548
}
36-
xhr.setRequestHeader("X-CodePush-Plugin-Name", "cordova-plugin-code-push");
37-
xhr.setRequestHeader("X-CodePush-Plugin-Version", cordova.require("cordova/plugin_list").metadata["cordova-plugin-code-push"]);
38-
xhr.setRequestHeader("X-CodePush-SDK-Version", cordova.require("cordova/plugin_list").metadata["code-push"]);
39-
xhr.send(requestBody);
49+
options.responseType = "text";
50+
cordova.plugin.http.sendRequest(url, options, function (success) {
51+
requestCallback && requestCallback(null, {
52+
body: success.data,
53+
statusCode: success.status,
54+
});
55+
}, function (failure) {
56+
requestCallback && requestCallback(new Error(failure.error), null);
57+
});
4058
};
41-
HttpRequester.prototype.getHttpMethodName = function (verb) {
59+
HttpRequester.getInitialOptionsForVerb = function (verb) {
4260
switch (verb) {
4361
case 0:
44-
return "GET";
45-
case 7:
46-
return "CONNECT";
62+
return { method: "get" };
4763
case 4:
48-
return "DELETE";
64+
return { method: "delete" };
4965
case 1:
50-
return "HEAD";
51-
case 6:
52-
return "OPTIONS";
66+
return { method: "head" };
5367
case 8:
54-
return "PATCH";
68+
return { method: "patch" };
5569
case 2:
56-
return "POST";
70+
return { method: "post" };
5771
case 3:
58-
return "PUT";
72+
return { method: "put" };
5973
case 5:
60-
return "TRACE";
74+
case 6:
75+
case 7:
6176
default:
62-
return null;
77+
return new ((function (_super) {
78+
__extends(UnsupportedMethodError, _super);
79+
function UnsupportedMethodError() {
80+
return _super !== null && _super.apply(this, arguments) || this;
81+
}
82+
return UnsupportedMethodError;
83+
}(Error)))("Unsupported HTTP method code [" + verb + "]");
6384
}
6485
};
6586
return HttpRequester;

bin/www/remotePackage.js

+24-20
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,21 @@ var __extends = (this && this.__extends) || (function () {
2323
})();
2424
var LocalPackage = require("./localPackage");
2525
var Package = require("./package");
26+
var FileUtil = require("./fileUtil");
2627
var NativeAppInfo = require("./nativeAppInfo");
2728
var CodePushUtil = require("./codePushUtil");
2829
var Sdk = require("./sdk");
2930
var RemotePackage = (function (_super) {
3031
__extends(RemotePackage, _super);
3132
function RemotePackage() {
32-
return _super !== null && _super.apply(this, arguments) || this;
33+
var _this = _super.call(this) || this;
34+
_this.isDownloading = false;
35+
FileUtil.getDataDirectory(LocalPackage.DownloadDir, true, function (error, _) {
36+
if (error) {
37+
CodePushUtil.logError("Can't create directory for download update.", error);
38+
}
39+
});
40+
return _this;
3341
}
3442
RemotePackage.prototype.download = function (successCallback, errorCallback, downloadProgress) {
3543
var _this = this;
@@ -39,9 +47,15 @@ var RemotePackage = (function (_super) {
3947
CodePushUtil.invokeErrorCallback(new Error("The remote package does not contain a download URL."), errorCallback);
4048
}
4149
else {
42-
this.currentFileTransfer = new FileTransfer();
43-
var downloadSuccess = function (fileEntry) {
44-
_this.currentFileTransfer = null;
50+
this.isDownloading = true;
51+
var onFileError_1 = function (fileError, stage) {
52+
var error = new Error("Could not access local package. Stage:" + stage + "Error code: " + fileError.code);
53+
CodePushUtil.invokeErrorCallback(error, errorCallback);
54+
CodePushUtil.logMessage(stage + ":" + fileError);
55+
_this.isDownloading = false;
56+
};
57+
var onFileReady = function (fileEntry) {
58+
_this.isDownloading = false;
4559
fileEntry.file(function (file) {
4660
NativeAppInfo.isFailedUpdate(_this.packageHash, function (installFailed) {
4761
var localPackage = new LocalPackage();
@@ -58,21 +72,11 @@ var RemotePackage = (function (_super) {
5872
successCallback && successCallback(localPackage);
5973
Sdk.reportStatusDownload(localPackage, localPackage.deploymentKey);
6074
});
61-
}, function (fileError) {
62-
CodePushUtil.invokeErrorCallback(new Error("Could not access local package. Error code: " + fileError.code), errorCallback);
63-
});
64-
};
65-
var downloadError = function (error) {
66-
_this.currentFileTransfer = null;
67-
CodePushUtil.invokeErrorCallback(new Error(error.body), errorCallback);
68-
};
69-
this.currentFileTransfer.onprogress = function (progressEvent) {
70-
if (downloadProgress) {
71-
var dp = { receivedBytes: progressEvent.loaded, totalBytes: progressEvent.total };
72-
downloadProgress(dp);
73-
}
75+
}, function (fileError) { return onFileError_1(fileError, "READ_FILE"); });
7476
};
75-
this.currentFileTransfer.download(this.downloadUrl, cordova.file.dataDirectory + LocalPackage.DownloadDir + "/" + LocalPackage.PackageUpdateFileName, downloadSuccess, downloadError);
77+
var filedir = cordova.file.dataDirectory + LocalPackage.DownloadDir + "/";
78+
var filename = LocalPackage.PackageUpdateFileName;
79+
cordova.plugin.http.downloadFile(this.downloadUrl, {}, {}, filedir + filename, onFileReady, onFileError_1);
7680
}
7781
}
7882
catch (e) {
@@ -81,8 +85,8 @@ var RemotePackage = (function (_super) {
8185
};
8286
RemotePackage.prototype.abortDownload = function (abortSuccess, abortError) {
8387
try {
84-
if (this.currentFileTransfer) {
85-
this.currentFileTransfer.abort();
88+
if (this.isDownloading) {
89+
this.isDownloading = false;
8690
abortSuccess && abortSuccess();
8791
}
8892
}

hooks/afterPluginAdd.js

-7
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,6 @@ module.exports = function (ctx) {
4646
plugins = execSync(cordovaCLI + ' plugin').toString();
4747
}
4848

49-
if (!isPluginInListOrInXmlConfig("cordova-plugin-file-transfer", plugins)) {
50-
console.log("Adding the [email protected]... ");
51-
var output = execSync(cordovaCLI + ' plugin add [email protected]').toString();
52-
console.log(output);
53-
plugins = execSync(cordovaCLI + ' plugin').toString();
54-
}
55-
5649
if (!isPluginInListOrInXmlConfig("cordova-plugin-zip", plugins)) {
5750
console.log("Adding the [email protected]... ");
5851
var output = execSync(cordovaCLI + ' plugin add [email protected]').toString();

plugin.xml

+4-1
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@
55
<license>MIT</license>
66
<keywords>cordova,code,push</keywords>
77
<repo>https://github.com/Microsoft/cordova-plugin-code-push.git</repo>
8-
8+
99
<dependency id="code-push" version="3.0.1" />
1010
<dependency id="cordova-plugin-dialogs" version=">=1.1.1" />
1111
<dependency id="cordova-plugin-device" version=">=1.1.0" />
12+
<dependency id="cordova-plugin-file" version=">=6.0.1" />
13+
<dependency id="cordova-plugin-advanced-http" version=">=2.2.0" />
14+
<dependency id="cordova-plugin-zip" version=">=3.1.0" />
1215

1316
<hook type="after_plugin_add" src="hooks/afterPluginAdd.js" />
1417

test/template/build.json

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{ "ios": { "debug": { "buildFlag": [ "-UseModernBuildSystem=0" ] }, "release": { "buildFlag": [ "-UseModernBuildSystem=0" ] } } }

typings/codePush.d.ts

+85-1
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,92 @@
44
// Copyright (c) Microsoft Corporation
55
// All rights reserved.
66
// Licensed under the MIT license.
7+
/// <reference types="cordova-plugin-file" />
8+
9+
// Types used in file handling
10+
/**
11+
* A function which accepts @type {FileEntry} containing a file
12+
*/
13+
type FileSaverCompletionHandler = (entry: FileEntry) => void;
14+
/**
15+
* A function which is called if file handling has failed
16+
*/
17+
type FileSaverErrorHandler = (error: FileError, at: string) => void;
18+
19+
/**
20+
* @namespace AdvancedHttp describes the select types from cordova-plugin-advanced-http
21+
* The plugin authors do not provide typescript typings, relying on ionic-native typings,
22+
* which require the project to use ionic promisify-style plugin versions.
23+
*
24+
* @see https://github.com/silkimen/cordova-plugin-advanced-http/issues/32
25+
*
26+
* For additional type documentation:
27+
* - @see README for cordova-plugin-advanced-http and the
28+
* - @see https://github.com/ionic-team/ionic-native/blob/master/src/%40ionic-native/plugins/http/index.ts
29+
* for partial typings provided by ionic
30+
*/
31+
declare namespace AdvancedHttp {
32+
33+
/**
34+
* Response is passed to @method sendRequest callbacks.
35+
*/
36+
export interface Response {
37+
/**
38+
* The status number of the response
39+
*/
40+
status: number;
41+
/**
42+
* The headers of the response
43+
*/
44+
headers: any;
45+
/**
46+
* The URL of the response. This property will be the final URL obtained after any redirects.
47+
*/
48+
url: string;
49+
/**
50+
* The data that is in the response. This property usually exists when a promise returned by a request method resolves.
51+
*/
52+
data?: any;
53+
/**
54+
* Error response from the server. This property usually exists when a promise returned by a request method rejects.
55+
*/
56+
error?: string;
57+
}
58+
59+
/**
60+
* Options object configures @method sendRequest calls
61+
*/
62+
export interface Options {
63+
method: 'get' | 'post' | 'put' | 'patch' | 'head' | 'delete' | 'upload' | 'download';
64+
data?: { [index: string]: any };
65+
params?: { [index: string]: string | number };
66+
serializer?: 'json' | 'urlencoded' | 'utf8';
67+
timeout?: number;
68+
headers?: { [index: string]: string };
69+
filePath?: string | string[];
70+
name?: string | string[];
71+
responseType?: 'text' | 'arraybuffer' | 'blob' | 'json';
72+
}
73+
74+
export class Plugin {
75+
/**
76+
* setHeader sets global headers for cordova-plugin-advanced-http calls
77+
*/
78+
setHeader(arg1: string, arg2: string, arg3?: string): void;
79+
/**
80+
* sendRequest handles the lifetime of an HTTP call
81+
*/
82+
sendRequest(url: string, options: Options, onSuccess: (r: Response) => void, onError: (r: Response) => void): void;
83+
/**
84+
* downloadFile wraps @method sendRequest to provide an easy interface for working with files
85+
*/
86+
downloadFile(url: string, body: object, headers: object, filePath: string, onSuccess: FileSaverCompletionHandler, onFailure: FileSaverErrorHandler): void;
87+
}
88+
89+
}
790

891
declare module Http {
92+
// Integer based verbs that will be passed by Acquisition SDK
993
export const enum Verb {
1094
GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, CONNECT, PATCH
1195
}
@@ -405,4 +489,4 @@ interface DownloadProgress {
405489
interface DeploymentResult {
406490
deployDir: DirectoryEntry,
407491
isDiffUpdate: boolean
408-
}
492+
}

www/codePush.ts

-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
/// <reference path="../typings/codePush.d.ts" />
22
/// <reference types="cordova-plugin-file" />
3-
/// <reference types="cordova-plugin-file-transfer" />
43
/// <reference types="cordova" />
54
/// <reference types="cordova-plugin-dialogs" />
65

www/fileUtil.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -281,8 +281,8 @@ class FileUtil {
281281
public static readFileEntry(fileEntry: FileEntry, callback: Callback<string>): void {
282282
fileEntry.file((file: File) => {
283283
var fileReader = new FileReader();
284-
fileReader.onloadend = (ev: any) => {
285-
callback(null, ev.target.result);
284+
fileReader.onloadend = (ev: ProgressEvent) => {
285+
callback(null, fileReader.result as string);
286286
};
287287

288288
fileReader.onerror = () => {

0 commit comments

Comments
 (0)