@revopush/react-native-code-push 1.4.0 → 2.5.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/CodePush.js +8 -5
  2. package/CodePush.podspec +9 -0
  3. package/README.md +7 -6
  4. package/android/build.gradle +52 -40
  5. package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  6. package/android/gradle/wrapper/gradle-wrapper.properties +3 -1
  7. package/android/gradle.properties +1 -1
  8. package/android/libs/revopush-diff-release-v0.0.1.aar +0 -0
  9. package/android/proguard-rules.pro +1 -1
  10. package/android/settings.gradle +31 -0
  11. package/android/src/main/java/com/microsoft/codepush/react/CodePush.java +8 -4
  12. package/android/src/main/java/com/microsoft/codepush/react/CodePushConstants.java +11 -7
  13. package/android/src/main/java/com/microsoft/codepush/react/CodePushNativeModule.java +48 -41
  14. package/android/src/main/java/com/microsoft/codepush/react/CodePushUpdateManager.java +67 -175
  15. package/android/src/main/java/com/microsoft/codepush/react/CodePushUpdateUtils.java +7 -244
  16. package/android/src/main/java/com/microsoft/codepush/react/CodePushUtils.java +16 -51
  17. package/android/src/main/java/com/microsoft/codepush/react/FileUtils.java +1 -130
  18. package/ios/CodePush/CodePush.h +1 -30
  19. package/ios/CodePush/CodePush.m +23 -7
  20. package/ios/CodePush/CodePushPackage.m +363 -294
  21. package/ios/CodePush/CodePushUpdateUtils.m +77 -28
  22. package/ios/CodePush.xcodeproj/project.pbxproj +0 -18
  23. package/ios/Frameworks/DiffUpdates.xcframework/Info.plist +44 -0
  24. package/ios/Frameworks/DiffUpdates.xcframework/ios-arm64/DiffUpdates.framework/DiffUpdates +0 -0
  25. package/ios/Frameworks/DiffUpdates.xcframework/ios-arm64/DiffUpdates.framework/Headers/DiffUpdates.h +61 -0
  26. package/ios/Frameworks/DiffUpdates.xcframework/ios-arm64/DiffUpdates.framework/Info.plist +0 -0
  27. package/ios/Frameworks/DiffUpdates.xcframework/ios-arm64/DiffUpdates.framework/Modules/module.modulemap +6 -0
  28. package/ios/Frameworks/DiffUpdates.xcframework/ios-arm64_x86_64-simulator/DiffUpdates.framework/DiffUpdates +0 -0
  29. package/ios/Frameworks/DiffUpdates.xcframework/ios-arm64_x86_64-simulator/DiffUpdates.framework/Headers/DiffUpdates.h +61 -0
  30. package/ios/Frameworks/DiffUpdates.xcframework/ios-arm64_x86_64-simulator/DiffUpdates.framework/Info.plist +0 -0
  31. package/ios/Frameworks/DiffUpdates.xcframework/ios-arm64_x86_64-simulator/DiffUpdates.framework/Modules/module.modulemap +6 -0
  32. package/ios/Frameworks/DiffUpdates.xcframework/ios-arm64_x86_64-simulator/DiffUpdates.framework/_CodeSignature/CodeDirectory +0 -0
  33. package/ios/Frameworks/DiffUpdates.xcframework/ios-arm64_x86_64-simulator/DiffUpdates.framework/_CodeSignature/CodeRequirements +0 -0
  34. package/ios/Frameworks/DiffUpdates.xcframework/ios-arm64_x86_64-simulator/DiffUpdates.framework/_CodeSignature/CodeRequirements-1 +0 -0
  35. package/ios/Frameworks/DiffUpdates.xcframework/ios-arm64_x86_64-simulator/DiffUpdates.framework/_CodeSignature/CodeResources +132 -0
  36. package/ios/Frameworks/DiffUpdates.xcframework/ios-arm64_x86_64-simulator/DiffUpdates.framework/_CodeSignature/CodeSignature +0 -0
  37. package/package.json +2 -2
  38. package/request-fetch-adapter.js +2 -2
  39. package/scripts/generateBundledResourcesHash.js +102 -65
  40. package/android/src/main/java/com/microsoft/codepush/react/TLSSocketFactory.java +0 -72
  41. package/ios/CodePush/CodePushDownloadHandler.m +0 -130
  42. package/ios/CodePush/CodePushErrorUtils.m +0 -20
  43. package/ios/CodePush/CodePushUtils.m +0 -9
  44. package/revopush-react-native-code-push-1.4.0-rc1.tgz +0 -0
@@ -0,0 +1,132 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>files</key>
6
+ <dict>
7
+ <key>Headers/DiffUpdates.h</key>
8
+ <data>
9
+ obtyjOKZntpytQhuejpfeMN0BoI=
10
+ </data>
11
+ <key>Info.plist</key>
12
+ <data>
13
+ 1nTR8o5HkR4SUcF0Z6umqipQPHI=
14
+ </data>
15
+ <key>Modules/module.modulemap</key>
16
+ <data>
17
+ MdjndwGRSccoMYmOwMDjozLG1jc=
18
+ </data>
19
+ </dict>
20
+ <key>files2</key>
21
+ <dict>
22
+ <key>Headers/DiffUpdates.h</key>
23
+ <dict>
24
+ <key>hash</key>
25
+ <data>
26
+ obtyjOKZntpytQhuejpfeMN0BoI=
27
+ </data>
28
+ <key>hash2</key>
29
+ <data>
30
+ DdvTO8aHHON6ybR/EQTihMgOY9j/pmVw7sekeFl71N4=
31
+ </data>
32
+ </dict>
33
+ <key>Modules/module.modulemap</key>
34
+ <dict>
35
+ <key>hash</key>
36
+ <data>
37
+ MdjndwGRSccoMYmOwMDjozLG1jc=
38
+ </data>
39
+ <key>hash2</key>
40
+ <data>
41
+ TkYpCqgNFTGwSnC7+iZu51GEITzi1EHKvjZj4HupKms=
42
+ </data>
43
+ </dict>
44
+ </dict>
45
+ <key>rules</key>
46
+ <dict>
47
+ <key>^.*</key>
48
+ <true/>
49
+ <key>^.*\.lproj/</key>
50
+ <dict>
51
+ <key>optional</key>
52
+ <true/>
53
+ <key>weight</key>
54
+ <real>1000</real>
55
+ </dict>
56
+ <key>^.*\.lproj/locversion.plist$</key>
57
+ <dict>
58
+ <key>omit</key>
59
+ <true/>
60
+ <key>weight</key>
61
+ <real>1100</real>
62
+ </dict>
63
+ <key>^Base\.lproj/</key>
64
+ <dict>
65
+ <key>weight</key>
66
+ <real>1010</real>
67
+ </dict>
68
+ <key>^version.plist$</key>
69
+ <true/>
70
+ </dict>
71
+ <key>rules2</key>
72
+ <dict>
73
+ <key>.*\.dSYM($|/)</key>
74
+ <dict>
75
+ <key>weight</key>
76
+ <real>11</real>
77
+ </dict>
78
+ <key>^(.*/)?\.DS_Store$</key>
79
+ <dict>
80
+ <key>omit</key>
81
+ <true/>
82
+ <key>weight</key>
83
+ <real>2000</real>
84
+ </dict>
85
+ <key>^.*</key>
86
+ <true/>
87
+ <key>^.*\.lproj/</key>
88
+ <dict>
89
+ <key>optional</key>
90
+ <true/>
91
+ <key>weight</key>
92
+ <real>1000</real>
93
+ </dict>
94
+ <key>^.*\.lproj/locversion.plist$</key>
95
+ <dict>
96
+ <key>omit</key>
97
+ <true/>
98
+ <key>weight</key>
99
+ <real>1100</real>
100
+ </dict>
101
+ <key>^Base\.lproj/</key>
102
+ <dict>
103
+ <key>weight</key>
104
+ <real>1010</real>
105
+ </dict>
106
+ <key>^Info\.plist$</key>
107
+ <dict>
108
+ <key>omit</key>
109
+ <true/>
110
+ <key>weight</key>
111
+ <real>20</real>
112
+ </dict>
113
+ <key>^PkgInfo$</key>
114
+ <dict>
115
+ <key>omit</key>
116
+ <true/>
117
+ <key>weight</key>
118
+ <real>20</real>
119
+ </dict>
120
+ <key>^embedded\.provisionprofile$</key>
121
+ <dict>
122
+ <key>weight</key>
123
+ <real>20</real>
124
+ </dict>
125
+ <key>^version\.plist$</key>
126
+ <dict>
127
+ <key>weight</key>
128
+ <real>20</real>
129
+ </dict>
130
+ </dict>
131
+ </dict>
132
+ </plist>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@revopush/react-native-code-push",
3
- "version": "1.4.0",
3
+ "version": "2.5.0-rc.0",
4
4
  "description": "React Native plugin for the CodePush service",
5
5
  "main": "CodePush.js",
6
6
  "typings": "typings/react-native-code-push.d.ts",
@@ -37,7 +37,7 @@
37
37
  "url": "https://github.com/revopush/react-native-code-push"
38
38
  },
39
39
  "dependencies": {
40
- "code-push": "4.2.3",
40
+ "@revopush/code-push": "4.3.0",
41
41
  "glob": "^7.1.7",
42
42
  "hoist-non-react-statics": "^3.3.2",
43
43
  "inquirer": "^8.1.5",
@@ -12,7 +12,7 @@ module.exports = {
12
12
  "Content-Type": "application/json",
13
13
  "X-CodePush-Plugin-Name": packageJson.name,
14
14
  "X-CodePush-Plugin-Version": packageJson.version,
15
- "X-CodePush-SDK-Version": packageJson.dependencies["code-push"]
15
+ "X-CodePush-SDK-Version": packageJson.dependencies["@revopush/code-push"]
16
16
  };
17
17
 
18
18
  if (requestBody && typeof requestBody === "object") {
@@ -49,4 +49,4 @@ function getHttpMethodName(verb) {
49
49
  "CONNECT",
50
50
  "PATCH"
51
51
  ][verb];
52
- }
52
+ }
@@ -17,10 +17,14 @@ var path = require("path");
17
17
 
18
18
  var getFilesInFolder = require("./getFilesInFolder");
19
19
 
20
- var CODE_PUSH_FOLDER_PREFIX = "CodePush";
21
- var CODE_PUSH_HASH_FILE_NAME = "CodePushHash";
22
- var CODE_PUSH_HASH_OLD_FILE_NAME = "CodePushHash.json";
23
- var HASH_ALGORITHM = "sha256";
20
+ const CODE_PUSH_FOLDER_PREFIX = "CodePush";
21
+ const CODE_PUSH_HASH_FILE_NAME = "CodePushHash";
22
+ const CODE_PUSH_METADATA_FILE_NAME = "CodePushMetadata";
23
+ const CODE_PUSH_PACKAGE_HASH = "packageHash"
24
+ const CODE_PUSH_BUNDLE_HASH = "bundleHash"
25
+ const CODE_PUSH_ASSET_HASH = "assetHash"
26
+ const CODE_PUSH_HASH_OLD_FILE_NAME = "CodePushHash.json";
27
+ const HASH_ALGORITHM = "sha256";
24
28
 
25
29
  var resourcesDir = process.argv[2];
26
30
  var jsBundleFilePath = process.argv[3];
@@ -30,96 +34,129 @@ var tempFileName = process.argv[5];
30
34
  var oldFileToModifiedTimeMap = {};
31
35
  var tempFileLocalPath = null;
32
36
  if (tempFileName) {
33
- tempFileLocalPath = path.join(require("os").tmpdir(), tempFileName);
34
- oldFileToModifiedTimeMap = require(tempFileLocalPath);
37
+ tempFileLocalPath = path.join(require("os").tmpdir(), tempFileName);
38
+ oldFileToModifiedTimeMap = require(tempFileLocalPath);
35
39
  }
36
40
  var resourceFiles = [];
37
41
 
38
42
  getFilesInFolder(resourcesDir, resourceFiles);
39
43
 
44
+ function getBundleResourceEntries(resourcesDir, assetsDir) {
45
+ const resourceFiles = [];
46
+ const assetFiles = [];
47
+ getFilesInFolder(resourcesDir, resourceFiles);
48
+ getFilesInFolder(assetsDir, assetFiles);
49
+ let resourceFilesRelative = resourceFiles.map((it) => path.relative(resourcesDir, it.path));
50
+ let assetsFilesRelative = assetFiles.map((it) => path.relative(assetsDir, it.path));
51
+
52
+ const normalizePath = (it) => path.join(CODE_PUSH_FOLDER_PREFIX, it).replace(/\\/g, "/")
53
+ return {
54
+ resources: Object.fromEntries(resourceFilesRelative.map((it) => [path.parse(it).name, normalizePath(it)])),
55
+ assets: Object.fromEntries(assetsFilesRelative.map((it) => [it.replace(/\\/g, "/"), normalizePath(it)]))
56
+ }
57
+ }
58
+
40
59
  var newFileToModifiedTimeMap = {};
41
60
 
42
- resourceFiles.forEach(function(resourceFile) {
43
- newFileToModifiedTimeMap[resourceFile.path.substring(resourcesDir.length)] = resourceFile.mtime;
61
+ resourceFiles.forEach(function (resourceFile) {
62
+ newFileToModifiedTimeMap[resourceFile.path.substring(resourcesDir.length)] = resourceFile.mtime;
44
63
  });
45
64
 
46
65
  var bundleGeneratedAssetFiles = [];
47
66
 
48
67
  for (var newFilePath in newFileToModifiedTimeMap) {
49
- if (!oldFileToModifiedTimeMap[newFilePath] || oldFileToModifiedTimeMap[newFilePath] < newFileToModifiedTimeMap[newFilePath].getTime()) {
50
- bundleGeneratedAssetFiles.push(newFilePath);
51
- }
68
+ if (!oldFileToModifiedTimeMap[newFilePath] || oldFileToModifiedTimeMap[newFilePath] < newFileToModifiedTimeMap[newFilePath].getTime()) {
69
+ bundleGeneratedAssetFiles.push(newFilePath);
70
+ }
52
71
  }
53
72
 
54
73
  var manifest = [];
55
74
 
56
75
  if (bundleGeneratedAssetFiles.length) {
57
- bundleGeneratedAssetFiles.forEach(function(assetFile) {
58
- // Generate hash for each asset file
59
- addFileToManifest(resourcesDir, assetFile, manifest, function() {
60
- if (manifest.length === bundleGeneratedAssetFiles.length) {
61
- addJsBundleAndMetaToManifest();
62
- }
63
- });
76
+ bundleGeneratedAssetFiles.forEach(function (assetFile) {
77
+ // Generate hash for each asset file
78
+ addFileToManifest(resourcesDir, assetFile, manifest, function () {
79
+ if (manifest.length === bundleGeneratedAssetFiles.length) {
80
+ addJsBundleAndMetaToManifest();
81
+ }
64
82
  });
83
+ });
65
84
  } else {
66
- addJsBundleAndMetaToManifest();
85
+ addJsBundleAndMetaToManifest();
67
86
  }
68
87
 
69
88
  function addJsBundleAndMetaToManifest() {
70
- addFileToManifest(path.dirname(jsBundleFilePath), path.basename(jsBundleFilePath), manifest, function() {
71
- var jsBundleMetaFilePath = jsBundleFilePath + ".meta";
72
- addFileToManifest(path.dirname(jsBundleMetaFilePath), path.basename(jsBundleMetaFilePath), manifest, function() {
73
- manifest = manifest.sort();
74
- var finalHash = crypto.createHash(HASH_ALGORITHM)
75
- .update(JSON.stringify(manifest))
76
- .digest("hex");
77
-
78
- console.log(finalHash);
79
-
80
- var savedResourcesManifestPath = assetsDir + "/" + CODE_PUSH_HASH_FILE_NAME;
81
- fs.writeFileSync(savedResourcesManifestPath, finalHash);
82
-
83
- // "CodePushHash.json" file name breaks flow type checking.
84
- // To fix the issue we need to delete "CodePushHash.json" file and
85
- // use "CodePushHash" file name instead to store the hash value.
86
- // Relates to https://github.com/microsoft/react-native-code-push/issues/577
87
- var oldSavedResourcesManifestPath = assetsDir + "/" + CODE_PUSH_HASH_OLD_FILE_NAME;
88
- if (fs.existsSync(oldSavedResourcesManifestPath)) {
89
- fs.unlinkSync(oldSavedResourcesManifestPath);
90
- }
91
- });
89
+ addFileToManifest(path.dirname(jsBundleFilePath), path.basename(jsBundleFilePath), manifest, function (jsBundleFileHash) {
90
+ var jsBundleMetaFilePath = jsBundleFilePath + ".meta";
91
+ addFileToManifest(path.dirname(jsBundleMetaFilePath), path.basename(jsBundleMetaFilePath), manifest, function () {
92
+ manifest = manifest.sort();
93
+ const finalHash = crypto.createHash(HASH_ALGORITHM)
94
+ .update(JSON.stringify(manifest))
95
+ .digest("hex");
96
+
97
+ const bundleHashDada = path.join(CODE_PUSH_FOLDER_PREFIX, path.basename(jsBundleFilePath)).replace(/\\/g, "/") + ":" + jsBundleFileHash;
98
+ const bundleHash = crypto.createHash(HASH_ALGORITHM)
99
+ .update(JSON.stringify([bundleHashDada]))
100
+ .digest("hex");
101
+
102
+ const assetHash = crypto.createHash(HASH_ALGORITHM)
103
+ .update(JSON.stringify([...manifest].filter(it => it !== bundleHashDada).sort()))
104
+ .digest("hex");
105
+
106
+ const manifestMetadata = {
107
+ [CODE_PUSH_PACKAGE_HASH]: finalHash,
108
+ [CODE_PUSH_BUNDLE_HASH]: bundleHash,
109
+ [CODE_PUSH_ASSET_HASH]: assetHash, ...(getBundleResourceEntries(resourcesDir, assetsDir))
110
+ }
111
+
112
+ console.log(finalHash);
113
+
114
+ fs.writeFileSync(path.join(assetsDir, CODE_PUSH_HASH_FILE_NAME), finalHash);
115
+ fs.writeFileSync(path.join(assetsDir, CODE_PUSH_METADATA_FILE_NAME), JSON.stringify(manifestMetadata));
116
+
117
+ // "CodePushHash.json" file name breaks flow type checking.
118
+ // To fix the issue we need to delete "CodePushHash.json" file and
119
+ // use "CodePushHash" file name instead to store the hash value.
120
+ // Relates to https://github.com/microsoft/react-native-code-push/issues/577
121
+ var oldSavedResourcesManifestPath = assetsDir + "/" + CODE_PUSH_HASH_OLD_FILE_NAME;
122
+ if (fs.existsSync(oldSavedResourcesManifestPath)) {
123
+ fs.unlinkSync(oldSavedResourcesManifestPath);
124
+ }
92
125
  });
126
+ });
93
127
  }
94
128
 
95
129
  function addFileToManifest(folder, assetFile, manifest, done) {
96
- var fullFilePath = path.join(folder, assetFile);
97
- if (!fileExists(fullFilePath)) {
98
- done();
99
- return;
100
- }
101
-
102
- var readStream = fs.createReadStream(path.join(folder, assetFile));
103
- var hashStream = crypto.createHash(HASH_ALGORITHM);
104
-
105
- readStream.pipe(hashStream)
106
- .on("error", function(error) {
107
- throw error;
108
- })
109
- .on("finish", function() {
110
- hashStream.end();
111
- var buffer = hashStream.read();
112
- var fileHash = buffer.toString("hex");
113
- manifest.push(path.join(CODE_PUSH_FOLDER_PREFIX, assetFile).replace(/\\/g, "/") + ":" + fileHash);
114
- done();
115
- });
130
+ var fullFilePath = path.join(folder, assetFile);
131
+ if (!fileExists(fullFilePath)) {
132
+ done(undefined);
133
+ return;
134
+ }
135
+
136
+ var readStream = fs.createReadStream(path.join(folder, assetFile));
137
+ var hashStream = crypto.createHash(HASH_ALGORITHM);
138
+
139
+ readStream.pipe(hashStream)
140
+ .on("error", function (error) {
141
+ throw error;
142
+ })
143
+ .on("finish", function () {
144
+ hashStream.end();
145
+ var buffer = hashStream.read();
146
+ var fileHash = buffer.toString("hex");
147
+ manifest.push(path.join(CODE_PUSH_FOLDER_PREFIX, assetFile).replace(/\\/g, "/") + ":" + fileHash);
148
+ done(fileHash);
149
+ });
116
150
  }
117
151
 
118
152
  function fileExists(file) {
119
- try { return fs.statSync(file).isFile(); }
120
- catch (e) { return false; }
153
+ try {
154
+ return fs.statSync(file).isFile();
155
+ } catch (e) {
156
+ return false;
157
+ }
121
158
  }
122
159
 
123
160
  if (tempFileLocalPath) {
124
- fs.unlinkSync(tempFileLocalPath);
125
- }
161
+ fs.unlinkSync(tempFileLocalPath);
162
+ }
@@ -1,72 +0,0 @@
1
- package com.microsoft.codepush.react;
2
-
3
- import java.io.IOException;
4
- import java.net.InetAddress;
5
- import java.net.Socket;
6
- import java.net.UnknownHostException;
7
- import java.security.KeyManagementException;
8
- import java.security.NoSuchAlgorithmException;
9
-
10
- import javax.net.ssl.SSLContext;
11
- import javax.net.ssl.SSLSocket;
12
- import javax.net.ssl.SSLSocketFactory;
13
-
14
- public class TLSSocketFactory extends SSLSocketFactory {
15
-
16
- private SSLSocketFactory delegate;
17
-
18
- public TLSSocketFactory() throws KeyManagementException, NoSuchAlgorithmException {
19
- SSLContext context = SSLContext.getInstance("TLS");
20
- context.init(null, null, null);
21
- delegate = context.getSocketFactory();
22
- }
23
-
24
- @Override
25
- public String[] getDefaultCipherSuites() {
26
- return delegate.getDefaultCipherSuites();
27
- }
28
-
29
- @Override
30
- public String[] getSupportedCipherSuites() {
31
- return delegate.getSupportedCipherSuites();
32
- }
33
-
34
- @Override
35
- public Socket createSocket() throws IOException {
36
- return enableTLSOnSocket(delegate.createSocket());
37
- }
38
-
39
- @Override
40
- public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
41
- return enableTLSOnSocket(delegate.createSocket(s, host, port, autoClose));
42
- }
43
-
44
- @Override
45
- public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
46
- return enableTLSOnSocket(delegate.createSocket(host, port));
47
- }
48
-
49
- @Override
50
- public Socket createSocket(String host, int port, InetAddress localHost, int localPort)
51
- throws IOException, UnknownHostException {
52
- return enableTLSOnSocket(delegate.createSocket(host, port, localHost, localPort));
53
- }
54
-
55
- @Override
56
- public Socket createSocket(InetAddress host, int port) throws IOException {
57
- return enableTLSOnSocket(delegate.createSocket(host, port));
58
- }
59
-
60
- @Override
61
- public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort)
62
- throws IOException {
63
- return enableTLSOnSocket(delegate.createSocket(address, port, localAddress, localPort));
64
- }
65
-
66
- private Socket enableTLSOnSocket(Socket socket) {
67
- if (socket != null && (socket instanceof SSLSocket)) {
68
- ((SSLSocket) socket).setEnabledProtocols(new String[] { "TLSv1.1", "TLSv1.2" });
69
- }
70
- return socket;
71
- }
72
- }
@@ -1,130 +0,0 @@
1
- #import "CodePush.h"
2
-
3
- @implementation CodePushDownloadHandler {
4
- // Header chars used to determine if the file is a zip.
5
- char _header[4];
6
- }
7
-
8
- - (id)init:(NSString *)downloadFilePath
9
- operationQueue:(dispatch_queue_t)operationQueue
10
- progressCallback:(void (^)(long long, long long))progressCallback
11
- doneCallback:(void (^)(BOOL))doneCallback
12
- failCallback:(void (^)(NSError *err))failCallback {
13
- self.outputFileStream = [NSOutputStream outputStreamToFileAtPath:downloadFilePath
14
- append:NO];
15
- self.receivedContentLength = 0;
16
- self.operationQueue = operationQueue;
17
- self.progressCallback = progressCallback;
18
- self.doneCallback = doneCallback;
19
- self.failCallback = failCallback;
20
- return self;
21
- }
22
-
23
- - (void)download:(NSString *)url {
24
- self.downloadUrl = url;
25
- NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]
26
- cachePolicy:NSURLRequestUseProtocolCachePolicy
27
- timeoutInterval:60.0];
28
- NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request
29
- delegate:self
30
- startImmediately:NO];
31
- if ([NSOperationQueue instancesRespondToSelector:@selector(setUnderlyingQueue:)]) {
32
- NSOperationQueue *delegateQueue = [NSOperationQueue new];
33
- delegateQueue.underlyingQueue = self.operationQueue;
34
- [connection setDelegateQueue:delegateQueue];
35
- } else {
36
- [connection scheduleInRunLoop:[NSRunLoop mainRunLoop]
37
- forMode:NSDefaultRunLoopMode];
38
- }
39
-
40
- [connection start];
41
- }
42
-
43
- #pragma mark NSURLConnection Delegate Methods
44
-
45
- - (NSCachedURLResponse *)connection:(NSURLConnection *)connection
46
- willCacheResponse:(NSCachedURLResponse*)cachedResponse {
47
- // Return nil to indicate not necessary to store a cached response for this connection
48
- return nil;
49
- }
50
-
51
- - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
52
- if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
53
- NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];
54
- if (statusCode >= 400) {
55
- [self.outputFileStream close];
56
- [connection cancel];
57
- NSError *err = [CodePushErrorUtils errorWithMessage:[NSString stringWithFormat: @"Received %ld response from %@", (long)statusCode, self.downloadUrl]];
58
- self.failCallback(err);
59
- return;
60
- }
61
- }
62
-
63
- self.expectedContentLength = response.expectedContentLength;
64
- [self.outputFileStream open];
65
- }
66
-
67
- - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
68
- if (self.receivedContentLength < 4) {
69
- for (int i = 0; i < [data length]; i++) {
70
- int headerOffset = (int)self.receivedContentLength + i;
71
- if (headerOffset >= 4) {
72
- break;
73
- }
74
-
75
- const char *bytes = [data bytes];
76
- _header[headerOffset] = bytes[i];
77
- }
78
- }
79
-
80
- self.receivedContentLength = self.receivedContentLength + [data length];
81
-
82
- NSInteger bytesLeft = [data length];
83
-
84
- do {
85
- NSInteger bytesWritten = [self.outputFileStream write:[data bytes]
86
- maxLength:bytesLeft];
87
- if (bytesWritten == -1) {
88
- break;
89
- }
90
-
91
- bytesLeft -= bytesWritten;
92
- } while (bytesLeft > 0);
93
-
94
- self.progressCallback(self.expectedContentLength, self.receivedContentLength);
95
-
96
- // bytesLeft should not be negative.
97
- assert(bytesLeft >= 0);
98
-
99
- if (bytesLeft) {
100
- [self.outputFileStream close];
101
- [connection cancel];
102
- self.failCallback([self.outputFileStream streamError]);
103
- }
104
- }
105
-
106
- - (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error
107
- {
108
- [self.outputFileStream close];
109
- self.failCallback(error);
110
- }
111
-
112
- - (void)connectionDidFinishLoading:(NSURLConnection *)connection {
113
- [self.outputFileStream close];
114
- if (self.receivedContentLength < 1) {
115
- NSError *err = [CodePushErrorUtils errorWithMessage:[NSString stringWithFormat:@"Received empty response from %@", self.downloadUrl]];
116
- self.failCallback(err);
117
- return;
118
- }
119
-
120
- // expectedContentLength might be -1 when NSURLConnection don't know the length(e.g. response encode with gzip)
121
- if (self.expectedContentLength > 0) {
122
- // We should have received all of the bytes if this is called.
123
- assert(self.receivedContentLength == self.expectedContentLength);
124
- }
125
-
126
- BOOL isZip = _header[0] == 'P' && _header[1] == 'K' && _header[2] == 3 && _header[3] == 4;
127
- self.doneCallback(isZip);
128
- }
129
-
130
- @end
@@ -1,20 +0,0 @@
1
- #import "CodePush.h"
2
-
3
- @implementation CodePushErrorUtils
4
-
5
- static NSString *const CodePushErrorDomain = @"CodePushError";
6
- static const int CodePushErrorCode = -1;
7
-
8
- + (NSError *)errorWithMessage:(NSString *)errorMessage
9
- {
10
- return [NSError errorWithDomain:CodePushErrorDomain
11
- code:CodePushErrorCode
12
- userInfo:@{ NSLocalizedDescriptionKey: NSLocalizedString(errorMessage, nil) }];
13
- }
14
-
15
- + (BOOL)isCodePushError:(NSError *)err
16
- {
17
- return err != nil && [CodePushErrorDomain isEqualToString:err.domain];
18
- }
19
-
20
- @end
@@ -1,9 +0,0 @@
1
- #import "CodePush.h"
2
-
3
- void CPLog(NSString *formatString, ...) {
4
- va_list args;
5
- va_start(args, formatString);
6
- NSString *prependedFormatString = [NSString stringWithFormat:@"\n[CodePush] %@", formatString];
7
- NSLogv(prependedFormatString, args);
8
- va_end(args);
9
- }