fix(iOS): Images don't render on iOS 14 with RN < 0.63.2 (#260)

This change monkey patches React Native on versions prior to 0.63.2 to
fix a bug with images not rendering when on iOS 14.

See https://github.com/facebook/react-native/pull/29420.
This commit is contained in:
Tommy Nguyen 2020-12-17 01:57:34 +01:00 коммит произвёл GitHub
Родитель 7c39ea5497
Коммит 39bb7da286
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
5 изменённых файлов: 113 добавлений и 42 удалений

Просмотреть файл

@ -7,15 +7,15 @@
objects = {
/* Begin PBXBuildFile section */
1914199A234B2DD800D856AE /* RCTDevSupport+UIScene.m in Sources */ = {isa = PBXBuildFile; fileRef = 19141999234B2DD800D856AE /* RCTDevSupport+UIScene.m */; };
192DD201240FCAF5004E9CEB /* Manifest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192DD200240FCAF5004E9CEB /* Manifest.swift */; };
196C22622490CB7600449D3C /* React+Compatibility.m in Sources */ = {isa = PBXBuildFile; fileRef = 196C22602490CB7600449D3C /* React+Compatibility.m */; };
196C7215232F1788006556ED /* ReactInstance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 196C7214232F1788006556ED /* ReactInstance.swift */; };
196C724123319A85006556ED /* QRCodeReaderDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 196C724023319A85006556ED /* QRCodeReaderDelegate.swift */; };
1988284524105BEC005057FF /* UIViewController+ReactTestApp.m in Sources */ = {isa = PBXBuildFile; fileRef = 1988284424105BEC005057FF /* UIViewController+ReactTestApp.m */; };
19ECD0D6232ED425003D8557 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19ECD0D5232ED425003D8557 /* AppDelegate.swift */; };
19ECD0D8232ED425003D8557 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19ECD0D7232ED425003D8557 /* SceneDelegate.swift */; };
19ECD0DA232ED425003D8557 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19ECD0D9232ED425003D8557 /* ContentView.swift */; };
192DD201240FCAF5004E9CEB /* Manifest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192DD200240FCAF5004E9CEB /* Manifest.swift */; };
196C724123319A85006556ED /* QRCodeReaderDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 196C724023319A85006556ED /* QRCodeReaderDelegate.swift */; };
196C7215232F1788006556ED /* ReactInstance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 196C7214232F1788006556ED /* ReactInstance.swift */; };
19ECD0D8232ED425003D8557 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19ECD0D7232ED425003D8557 /* SceneDelegate.swift */; };
1914199A234B2DD800D856AE /* RCTDevSupport+UIScene.m in Sources */ = {isa = PBXBuildFile; fileRef = 19141999234B2DD800D856AE /* RCTDevSupport+UIScene.m */; };
196C22622490CB7600449D3C /* React+Compatibility.m in Sources */ = {isa = PBXBuildFile; fileRef = 196C22602490CB7600449D3C /* React+Compatibility.m */; };
1988284524105BEC005057FF /* UIViewController+ReactTestApp.m in Sources */ = {isa = PBXBuildFile; fileRef = 1988284424105BEC005057FF /* UIViewController+ReactTestApp.m */; };
19ECD0DC232ED427003D8557 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 19ECD0DB232ED427003D8557 /* Assets.xcassets */; };
19ECD0E2232ED427003D8557 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 19ECD0E0232ED427003D8557 /* LaunchScreen.storyboard */; };
19ECD0ED232ED428003D8557 /* ReactTestAppTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19ECD0EC232ED428003D8557 /* ReactTestAppTests.swift */; };
@ -220,8 +220,8 @@
19ECD0CA232ED425003D8557 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1100;
LastUpgradeCheck = 1220;
LastSwiftUpdateCheck = 1230;
LastUpgradeCheck = 1230;
ORGANIZATIONNAME = Microsoft;
TargetAttributes = {
19ECD0D1232ED425003D8557 = {

Просмотреть файл

@ -14,27 +14,10 @@
#import <React/RCTUtils.h>
#import <React/RCTVersion.h>
#import "React+Compatibility.h"
#if DEBUG
void swizzleSelector(Class class, SEL originalSelector, SEL swizzledSelector)
{
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
BOOL didAddMethod = class_addMethod(class,
originalSelector,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
class_replaceMethod(class,
swizzledSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
// MARK: - RCTRedBoxWindow
@protocol RCTRedBoxWindowActionDelegate;
@ -56,11 +39,11 @@ void swizzleSelector(Class class, SEL originalSelector, SEL swizzledSelector)
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class class = [self class];
swizzleSelector(class,
@selector(showErrorMessage:withStack:isUpdate:),
@selector(rta_showErrorMessage:withStack:isUpdate:));
swizzleSelector(class, @selector(dismiss), @selector(rta_dismiss));
swizzleSelector(class, @selector(makeKeyAndVisible), @selector(rta_makeKeyAndVisible));
RTASwizzleSelector(class,
@selector(showErrorMessage:withStack:isUpdate:),
@selector(rta_showErrorMessage:withStack:isUpdate:));
RTASwizzleSelector(class, @selector(dismiss), @selector(rta_dismiss));
RTASwizzleSelector(class, @selector(makeKeyAndVisible), @selector(rta_makeKeyAndVisible));
});
}
@ -103,9 +86,9 @@ void swizzleSelector(Class class, SEL originalSelector, SEL swizzledSelector)
}
if (@available(iOS 13.0, *)) {
swizzleSelector([self class],
@selector(showMessage:color:backgroundColor:),
@selector(rta_showMessage:color:backgroundColor:));
RTASwizzleSelector([self class],
@selector(showMessage:color:backgroundColor:),
@selector(rta_showMessage:color:backgroundColor:));
}
}

Просмотреть файл

@ -9,4 +9,6 @@
@class RCTBridge;
IMP RTASwizzleSelector(Class class, SEL originalSelector, SEL swizzledSelector);
void RTATriggerReloadCommand(RCTBridge *, NSString *reason);

Просмотреть файл

@ -9,8 +9,33 @@
#include <TargetConditionals.h>
#import <objc/runtime.h>
#import <React/RCTBridge.h>
IMP RTASwizzleSelector(Class class, SEL originalSelector, SEL swizzledSelector)
{
Method originalMethod = class_getInstanceMethod(class, originalSelector);
IMP originalImpl = method_getImplementation(originalMethod);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
BOOL didAddMethod = class_addMethod(class,
originalSelector,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
const char *type = method_getTypeEncoding(originalMethod);
class_replaceMethod(class, swizzledSelector, originalImpl, type);
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
return originalImpl;
}
// MARK: - [0.62] RCTTriggerReloadCommandListeners replaces -[RCTBridge reload]
// `RCTReloadCommand.h` is excluded from `react-native-macos`
// See https://github.com/microsoft/react-native-macos/blob/v0.61.39/React-Core.podspec#L66
#if REACT_NATIVE_VERSION >= 6200
@ -25,3 +50,64 @@ void RTATriggerReloadCommand(RCTBridge *bridge, NSString *reason)
RCTTriggerReloadCommandListeners(reason);
#endif
}
// MARK: - [0.63.2] Images do not render on iOS 14
// See https://github.com/facebook/react-native/pull/29420
#if !TARGET_OS_OSX && REACT_NATIVE_VERSION < 6302
#import <React/RCTUIImageViewAnimated.h>
@implementation RCTUIImageViewAnimated (ReactTestApp)
static void (*orig_displayLayer)(id, SEL, CALayer *);
+ (void)initialize
{
if ([self class] != [RCTUIImageViewAnimated class]) {
return;
}
if (@available(iOS 14.0, *)) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
IMP impl = RTASwizzleSelector(
[self class], @selector(displayLayer:), @selector(rta_displayLayer:));
orig_displayLayer = (void (*)(id, SEL, CALayer *))impl;
});
}
}
- (void)rta_displayLayer:(CALayer *)layer
{
/* The fix for images not rendering is to let UIImageView handle it when we
* are not animating. The following change was made in react-native#29420:
*
* diff --git a/Libraries/Image/RCTUIImageViewAnimated.m b/Libraries/Image/RCTUIImageViewAnimated.m
* index 93c6a2f02f5..f6fb5bc60cc 100644
* --- a/Libraries/Image/RCTUIImageViewAnimated.m
* +++ b/Libraries/Image/RCTUIImageViewAnimated.m
* @@ -285,6 +285,8 @@ static NSUInteger RCTDeviceFreeMemory() {
* if (_currentFrame) {
* layer.contentsScale = self.animatedImageScale;
* layer.contents = (__bridge id)_currentFrame.CGImage;
* + } else {
* + [super displayLayer:layer];
* }
* }
*
* The patch calls `super` when `_currentFrame` is `nil`. For our monkey
* patch, we'll invert the logic to let the original method handle the case
* where `_currentFrame` is missing.
*/
if ([self respondsToSelector:@selector(currentFrame)] &&
[self performSelector:@selector(currentFrame)] == nil) {
[super displayLayer:layer];
} else {
orig_displayLayer(self, @selector(displayLayer:), layer);
}
}
@end
#endif

Просмотреть файл

@ -8,13 +8,13 @@
/* Begin PBXBuildFile section */
193EF063247A736200BE8C79 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 193EF062247A736200BE8C79 /* AppDelegate.swift */; };
193EF08F247A799D00BE8C79 /* Manifest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 193EF08E247A799D00BE8C79 /* Manifest.swift */; };
193EF098247B130700BE8C79 /* ReactInstance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 193EF097247B130700BE8C79 /* ReactInstance.swift */; };
193EF065247A736200BE8C79 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 193EF064247A736200BE8C79 /* ViewController.swift */; };
196C22652490CBAB00449D3C /* React+Compatibility.m in Sources */ = {isa = PBXBuildFile; fileRef = 196C22632490CBAB00449D3C /* React+Compatibility.m */; };
193EF093247A830200BE8C79 /* UIViewController+ReactTestApp.m in Sources */ = {isa = PBXBuildFile; fileRef = 193EF091247A830200BE8C79 /* UIViewController+ReactTestApp.m */; };
193EF067247A736300BE8C79 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 193EF066247A736300BE8C79 /* Assets.xcassets */; };
193EF06A247A736300BE8C79 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 193EF068247A736300BE8C79 /* Main.storyboard */; };
193EF08F247A799D00BE8C79 /* Manifest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 193EF08E247A799D00BE8C79 /* Manifest.swift */; };
193EF093247A830200BE8C79 /* UIViewController+ReactTestApp.m in Sources */ = {isa = PBXBuildFile; fileRef = 193EF091247A830200BE8C79 /* UIViewController+ReactTestApp.m */; };
193EF098247B130700BE8C79 /* ReactInstance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 193EF097247B130700BE8C79 /* ReactInstance.swift */; };
196C22652490CBAB00449D3C /* React+Compatibility.m in Sources */ = {isa = PBXBuildFile; fileRef = 196C22632490CBAB00449D3C /* React+Compatibility.m */; };
19E791C024B08E1400FA6468 /* ReactTestAppTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19E791BF24B08E1400FA6468 /* ReactTestAppTests.swift */; };
19E791C324B08E4D00FA6468 /* ReactTestAppUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19E791C224B08E4D00FA6468 /* ReactTestAppUITests.swift */; };
/* End PBXBuildFile section */
@ -211,8 +211,8 @@
193EF057247A736100BE8C79 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1150;
LastUpgradeCheck = 1220;
LastSwiftUpdateCheck = 1230;
LastUpgradeCheck = 1230;
ORGANIZATIONNAME = Microsoft;
TargetAttributes = {
193EF05E247A736100BE8C79 = {