Crash solution when upgrading IOS 17 version in ReactNative

Solution to Crash when upgrading IOS 17 version in ReactNative

    • Crash solution when upgrading IOS 17 version in ReactNative
        • 1. Problem description
        • 2. Cause analysis
        • 3. Solution decision-making
          • 3.1 Set width and height to non-zero values
          • 3.2 Use the new UIGraphicsImageRenderer to replace the old version of UIGraphicsBeginImageContext
        • 4. Third-party libraries that may use this API
          • 4.1 react-native-fast-image
          • 4.2 react-native-linear-gradient
          • 4.3 There are also the following third-party libraries that use `UIGraphicsBeginImageContextWithOptions`:
        • 5. Reference address
1. Problem description

When using screenshots related to business, UIGraphicsBeginImageContextWithOptions & amp; & amp; UIGraphicsEndImageContext will report Assert.

The error message will be as follows:

  • UIGraphicsBeginImageContext() failed to allocate CGBitampContext: size={382, 0}, scale=3.000000, bitmapInfo=0x2002. Use UIGraphicsImageRenderer to avoid this assert.

Or it would be like this

  • *** Assertion failure in void _UIGraphicsBeginImageContextWithOptions(CGSize, BOOL, CGFloat, BOOL)(), UIGraphics.m:410
2. Cause analysis

After checking the API, I found that UIGraphicsBeginImageContext has been deprecated on iOS 17. Click here to see the official documentation https://developer.apple.com/documentation /uikit/1623922-uigraphicsbeginimagecontext

Can clearly see the deprecation for the following versions

  • iOS 2.0–17.0 Deprecated
  • iPadOS 2.0–17.0 Deprecated
  • Mac Catalyst 13.1–17.0 Deprecated
  • tvOS 9.0–17.0 Deprecated
  • watchOS 2.0–10.0 Deprecated
  • visionOS 1.0–1.0 Deprecated
3. Solution decision-making
3.1 Set width and height to non-zero values

When we ensure that the width and height of the api are not zero, it can be used normally. There are many places that need to be changed. It may be necessary to check every place in the business that is set to zero attributes.

3.2 Use the new UIGraphicsImageRenderer to replace the old version of UIGraphicsBeginImageContext

The changes are relatively small. You only need to change the native content in the third-party library. There is no need to verify every element involved in the business. You only need to verify that some pages are displayed normally.

4. Third-party libraries that may use this API
4.1 react-native-fast-image

Solution: react-native-fast-image official solution
Modify the node_modules file path: ios/FastImage/FFFastImageView.m

- (UIImage*) makeImage: (UIImage*)image withTint: (UIColor*)color {<!-- -->
    UIImage* newImage = [image imageWithRenderingMode: UIImageRenderingModeAlwaysTemplate];

    UIGraphicsImageRendererFormat *format = [UIGraphicsImageRendererFormat defaultFormat];
    UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:image.size format:format];

    UIImage *resultImage = [renderer imageWithActions:^(UIGraphicsImageRendererContext * _Nonnull rendererContext) {<!-- -->
        CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height);
        [color set];
        [newImage drawInRect:rect];
    }];

    return resultImage;
}


4.2 react-native-linear-gradient

Official solution: react-native-linear-gradient official solution

According to the official solution, a new version package has been provided in the npm warehouse. At this time, we can update the source code or directly update the version:

  • Download the latest version
    Download the latest version address: https://github.com/react-native-linear-gradient/react-native-linear-gradient/releases/tag/v2.8.3
    You can also go directly to the npm repository.

  • Update source code directly

If you want to update the source code, update the display function in the file path/node_modules/react-native-linear-gradient/ios/BVLinearGradientLayer.m.

- (void)display {<!-- -->
    [super display];

    // short circuit when height or width are 0. Fixes CGContext errors throwing
    if (self.bounds.size.height == 0 || self.bounds.size.width == 0) {<!-- -->
      return;
    }

    BOOL hasAlpha = NO;

    for (NSInteger i = 0; i < self.colors.count; i + + ) {<!-- -->
        hasAlpha = hasAlpha || CGColorGetAlpha(self.colors[i].CGColor) < 1.0;
    }

    if (@available(iOS 10.0, *)) {<!-- -->
        UIGraphicsImageRendererFormat *format;
        if (@available(iOS 11.0, *)) {<!-- -->
            format = [UIGraphicsImageRendererFormat preferredFormat];
        } else {<!-- -->
            format = [UIGraphicsImageRendererFormat defaultFormat];
        }
        format.opaque = !hasAlpha;
        UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:self.bounds.size format:format];
        UIImage *image = [renderer imageWithActions:^(UIGraphicsImageRendererContext * _Nonnull ref) {<!-- -->
            [self drawInContext:ref.CGContext];
        }];

        self.contents = (__bridge id _Nullable)(image.CGImage);
        self.contentsScale = image.scale;
    } else {<!-- -->
        UIGraphicsBeginImageContextWithOptions(self.bounds.size, !hasAlpha, 0.0);
        CGContextRef ref = UIGraphicsGetCurrentContext();
        [self drawInContext:ref];

        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
        self.contents = (__bridge id _Nullable)(image.CGImage);
        self.contentsScale = image.scale;

        UIGraphicsEndImageContext();
    }
}

The crash in my project is a problem with this library. When the gradient text has content, the display is normal, but when the text content does not exist, a crash occurs, which is very strange.

4.3 There are also the following third-party libraries that use UIGraphicsBeginImageContextWithOptions:
  • React native itself draws borders
  • react-native itself image processing /node_modules/react-native/Libraries/Image/RCTImageUtils.m
  • react-native-camera
  • react-native-view-shot
  • The react-native-svg file contains the address: node_modules/react-native-svg/apple/RNSVGRenderable.mm
  • TZImagePickerController in react-native-syan-image-picker

Other third-party libraries are not listed. You can search for UIGraphicsBeginImageContextWithOptions in Xcode to check whether it is used and verify whether the display is normal. If there is a problem with the display, you can go to the official Github corresponding to the third-party library to find a solution or replace it yourself.

5. Reference address

Apple official question: https://developer.apple.com/forums/thread/733326
Apple official question: https://developer.apple.com/forums/thread/731385
github issue: https://github.com/react-native-linear-gradient/react-native-linear-gradient/issues/637
github: https://github.com/ibireme/YYText/issues/984
github:https://github.com/muntius/react-native-fast-image/commit/fc2b8acd97f07989e312f5cbd61d2e541fda3611
github:https://github.com/DylanVann/react-native-fast-image/issues/1002