From 09bb761b25a7cdf9f6332441c35fe7edf85e7088 Mon Sep 17 00:00:00 2001 From: Nick Lockwood Date: Mon, 27 Jul 2015 09:11:15 -0700 Subject: [PATCH 1/5] Fixed RCTDownloadTaskWrapper crash on iOS7 Summary: This is a quick fix for the RCTDownloadTaskWrapper crashing on iOS 7. The issue was that the object returned by -[NSURLSession downloadTaskWithURL:] on iOS was not actually a subclass of NSURLSessionTask, so the category that adds associated blocks was not working. I've fixed that by making it a category on NSObject instead. --- Libraries/Image/RCTDownloadTaskWrapper.m | 44 +++++++++++------------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/Libraries/Image/RCTDownloadTaskWrapper.m b/Libraries/Image/RCTDownloadTaskWrapper.m index e9a64369b..152a19259 100644 --- a/Libraries/Image/RCTDownloadTaskWrapper.m +++ b/Libraries/Image/RCTDownloadTaskWrapper.m @@ -12,36 +12,33 @@ #import -static void *const RCTDownloadTaskWrapperCompletionBlockKey = (void *)&RCTDownloadTaskWrapperCompletionBlockKey; -static void *const RCTDownloadTaskWrapperProgressBlockKey = (void *)&RCTDownloadTaskWrapperProgressBlockKey; +@interface NSObject (RCTDownloadTaskWrapper) -@interface NSURLSessionTask (RCTDownloadTaskWrapper) - -@property (nonatomic, copy, setter=rct_setCompletionBlock:) RCTDataCompletionBlock rct_completionBlock; -@property (nonatomic, copy, setter=rct_setProgressBlock:) RCTDataProgressBlock rct_progressBlock; +@property (nonatomic, copy) RCTDataCompletionBlock reactCompletionBlock; +@property (nonatomic, copy) RCTDataProgressBlock reactProgressBlock; @end -@implementation NSURLSessionTask (RCTDownloadTaskWrapper) +@implementation NSObject (RCTDownloadTaskWrapper) -- (RCTDataCompletionBlock)rct_completionBlock +- (RCTDataCompletionBlock)reactCompletionBlock { - return objc_getAssociatedObject(self, RCTDownloadTaskWrapperCompletionBlockKey); + return objc_getAssociatedObject(self, _cmd); } -- (void)rct_setCompletionBlock:(RCTDataCompletionBlock)completionBlock +- (void)setReactCompletionBlock:(RCTDataCompletionBlock)completionBlock { - objc_setAssociatedObject(self, RCTDownloadTaskWrapperCompletionBlockKey, completionBlock, OBJC_ASSOCIATION_COPY_NONATOMIC); + objc_setAssociatedObject(self, @selector(reactCompletionBlock), completionBlock, OBJC_ASSOCIATION_COPY_NONATOMIC); } -- (RCTDataProgressBlock)rct_progressBlock +- (RCTDataProgressBlock)reactProgressBlock { - return objc_getAssociatedObject(self, RCTDownloadTaskWrapperProgressBlockKey); + return objc_getAssociatedObject(self, _cmd); } -- (void)rct_setProgressBlock:(RCTDataProgressBlock)progressBlock +- (void)setReactProgressBlock:(RCTDataProgressBlock)progressBlock { - objc_setAssociatedObject(self, RCTDownloadTaskWrapperProgressBlockKey, progressBlock, OBJC_ASSOCIATION_COPY_NONATOMIC); + objc_setAssociatedObject(self, @selector(reactProgressBlock), progressBlock, OBJC_ASSOCIATION_COPY_NONATOMIC); } @end @@ -63,9 +60,8 @@ static void *const RCTDownloadTaskWrapperProgressBlockKey = (void *)&RCTDownload - (NSURLSessionDownloadTask *)downloadData:(NSURL *)url progressBlock:(RCTDataProgressBlock)progressBlock completionBlock:(RCTDataCompletionBlock)completionBlock { NSURLSessionDownloadTask *task = [_URLSession downloadTaskWithURL:url]; - task.rct_completionBlock = completionBlock; - task.rct_progressBlock = progressBlock; - + task.reactCompletionBlock = completionBlock; + task.reactProgressBlock = progressBlock; return task; } @@ -73,28 +69,28 @@ static void *const RCTDownloadTaskWrapperProgressBlockKey = (void *)&RCTDownload - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location { - if (downloadTask.rct_completionBlock) { + if (downloadTask.reactCompletionBlock) { NSData *data = [NSData dataWithContentsOfURL:location]; dispatch_async(dispatch_get_main_queue(), ^{ - downloadTask.rct_completionBlock(downloadTask.response, data, nil); + downloadTask.reactCompletionBlock(downloadTask.response, data, nil); }); } } - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)didWriteData totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite; { - if (downloadTask.rct_progressBlock) { + if (downloadTask.reactProgressBlock) { dispatch_async(dispatch_get_main_queue(), ^{ - downloadTask.rct_progressBlock(totalBytesWritten, totalBytesExpectedToWrite); + downloadTask.reactProgressBlock(totalBytesWritten, totalBytesExpectedToWrite); }); } } - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { - if (error && task.rct_completionBlock) { + if (error && task.reactCompletionBlock) { dispatch_async(dispatch_get_main_queue(), ^{ - task.rct_completionBlock(nil, nil, error); + task.reactCompletionBlock(nil, nil, error); }); } } From b7253dc6045ce9cb37b7f6611a58da37e9746dd2 Mon Sep 17 00:00:00 2001 From: Martin Konicek Date: Mon, 27 Jul 2015 09:25:19 -0700 Subject: [PATCH 2/5] [ReactNative] PixelRatio docs Summary: Update docs for `PixelRatio` in preparation for open sourcing React Native for Android. See http://stackoverflow.com/questions/11581649/about-android-image-and-asset-sizes --- Libraries/Utilities/PixelRatio.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/Libraries/Utilities/PixelRatio.js b/Libraries/Utilities/PixelRatio.js index 7660fad30..940890cce 100644 --- a/Libraries/Utilities/PixelRatio.js +++ b/Libraries/Utilities/PixelRatio.js @@ -20,9 +20,11 @@ var Dimensions = require('Dimensions'); * * ### Displaying a line that's as thin as the device permits * - * A width of 1 is actually pretty thick on an iPhone 4+, we can do one that's - * thinner using a width of `1 / PixelRatio.get()`. It's a technique that works - * on all the devices independent of their pixel density. + * A width of 1 is actually pretty thick on devices with high pixel density + * (such as iPhone 4+ and many Android devices), we can make one that's + * thinner using a width of `1 / PixelRatio.get()`. + * It's a technique that works on all the devices independent of their + * pixel density. * * ``` * style={{ borderWidth: 1 / PixelRatio.get() }} @@ -46,12 +48,18 @@ class PixelRatio { /** * Returns the device pixel density. Some examples: * + * - PixelRatio.get() === 1 + * - mdpi Android devices (160 dpi) + * - PixelRatio.get() === 1.5 + * - hdpi Android devices (240 dpi) * - PixelRatio.get() === 2 * - iPhone 4, 4S * - iPhone 5, 5c, 5s * - iPhone 6 + * - xhdpi Android devices (320 dpi) * - PixelRatio.get() === 3 * - iPhone 6 plus + * - xxhdpi Android devices (480 dpi) * - PixelRatio.get() === 3.5 * - Nexus 6 */ @@ -68,6 +76,7 @@ class PixelRatio { * * Currently this is only implemented on Android and reflects the user preference set in * Settings > Display > Font size, on iOS it will always return the default pixel ratio. + * @platform android */ static getFontScale(): number { return Dimensions.get('window').fontScale || PixelRatio.get(); From 33e62f71f41b00a06bf6e24322c34b4465c6fb8d Mon Sep 17 00:00:00 2001 From: Martin Konicek Date: Mon, 27 Jul 2015 09:22:51 -0700 Subject: [PATCH 3/5] [ReactNative] CameraRoll docs Summary: In preparation for open sourcing React Native for Android, document which parts of the `CameraRoll` API are platform-specific. Renders like this: http://imgur.com/rbpXHKf We should improve docs generation for `@param`s. --- Libraries/CameraRoll/CameraRoll.js | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/Libraries/CameraRoll/CameraRoll.js b/Libraries/CameraRoll/CameraRoll.js index 1f5c6c22a..a710e7ec1 100644 --- a/Libraries/CameraRoll/CameraRoll.js +++ b/Libraries/CameraRoll/CameraRoll.js @@ -109,17 +109,28 @@ var getPhotosReturnChecker = createStrictShapeTypeChecker({ }).isRequired, }); +/** + * `CameraRoll` provides access to the local camera roll / gallery. + */ class CameraRoll { static GroupTypesOptions: Array; static AssetTypeOptions: Array; /** - * Saves the image with tag `tag` to the camera roll. + * Saves the image to the camera roll / gallery. * - * @param {string} tag - Can be any of the three kinds of tags we accept: - * 1. URL - * 2. assets-library tag - * 3. tag returned from storing an image in memory + * @param {string} tag On Android, this is a local URI, such + * as `"file:///sdcard/img.png"`. + * + * On iOS, the tag can be one of the following: + * + * - local URI + * - assets-library tag + * - a tag not maching any of the above, which means the image data will + * be stored in memory (and consume memory as long as the process is alive) + * + * @param successCallback Invoked with the value of `tag` on success. + * @param errorCallback Invoked with error message on error. */ static saveImageWithTag(tag, successCallback, errorCallback) { invariant( @@ -140,10 +151,10 @@ class CameraRoll { * Invokes `callback` with photo identifier objects from the local camera * roll of the device matching shape defined by `getPhotosReturnChecker`. * - * @param {object} params - See `getPhotosParamChecker`. - * @param {function} callback - Invoked with arg of shape defined by - * `getPhotosReturnChecker` on success. - * @param {function} errorCallback - Invoked with error message on error. + * @param {object} params See `getPhotosParamChecker`. + * @param {function} callback Invoked with arg of shape defined by + * `getPhotosReturnChecker` on success. + * @param {function} errorCallback Invoked with error message on error. */ static getPhotos(params, callback, errorCallback) { var metaCallback = callback; From 18e6094cabb82a5ae2110158f015ee2ea9ccc440 Mon Sep 17 00:00:00 2001 From: Christopher Chedeau Date: Mon, 27 Jul 2015 10:49:43 -0700 Subject: [PATCH 4/5] [ReactNative] Add overflow to the whitelisted Image props Summary: For some reason we're now spamming the logs everytime we render an Image because overflow is not defined in the whitelist. overflow: 'hidden' is needed for network images with cover mode. The way we currently define those is not optimal where we try to factor as many things as possible into distinct propTypes. However for Text we're not even using this but we are getting all the ones from View (which many do not apply) and remove some that aren't needed. It may be useful to cleanup this in the future but in the short term, it's better to remove this warning that doesn't have much value anyway. --- Libraries/Image/ImageStylePropTypes.js | 1 + Libraries/StyleSheet/StyleSheetValidation.js | 5 ----- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/Libraries/Image/ImageStylePropTypes.js b/Libraries/Image/ImageStylePropTypes.js index c70bee73a..c4ccfb578 100644 --- a/Libraries/Image/ImageStylePropTypes.js +++ b/Libraries/Image/ImageStylePropTypes.js @@ -24,6 +24,7 @@ var ImageStylePropTypes = { borderColor: ReactPropTypes.string, borderWidth: ReactPropTypes.number, borderRadius: ReactPropTypes.number, + overflow: ReactPropTypes.oneOf(['visible', 'hidden']), // iOS-Specific style to "tint" an image. // It changes the color of all the non-transparent pixels to the tintColor diff --git a/Libraries/StyleSheet/StyleSheetValidation.js b/Libraries/StyleSheet/StyleSheetValidation.js index be59b2ec5..f61decb3c 100644 --- a/Libraries/StyleSheet/StyleSheetValidation.js +++ b/Libraries/StyleSheet/StyleSheetValidation.js @@ -51,11 +51,6 @@ class StyleSheetValidation { static addValidStylePropTypes(stylePropTypes) { for (var key in stylePropTypes) { - invariant( - allStylePropTypes[key] === undefined || - allStylePropTypes[key] === stylePropTypes[key], - 'Attemped to redefine existing style prop type "' + key + '".' - ); allStylePropTypes[key] = stylePropTypes[key]; } } From 58a403d3c8f8b9ce1fae765d677fd535e6a9a11c Mon Sep 17 00:00:00 2001 From: Alex Kotliarskyi Date: Mon, 27 Jul 2015 12:13:34 -0700 Subject: [PATCH 5/5] [ReactNative] Pin babel version Summary: Currently minor version babel updates add and remove transforms, but internal version is checked in and pinned to 5.6.4. Until we figure out how to update internal deps systematically, we need to make sure OSS edition of RN matches internal, otherwise we get test failures due to package version mismatches. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b5f90776b..765c7a4a0 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "dependencies": { "absolute-path": "0.0.0", "babel": "5.4.3", - "babel-core": "^5.6.4", + "babel-core": "5.6.4", "chalk": "^1.0.0", "connect": "2.8.3", "debug": "~2.1.0",