From 3350ab442a0ef33bfccf4f8375eb71508922a79c Mon Sep 17 00:00:00 2001 From: Bohdan Artiukhov <69891500+bohdanprog@users.noreply.github.com> Date: Tue, 13 Aug 2024 10:45:10 +0200 Subject: [PATCH] fix: implementation toDataURL for iOS platform both architectures (#2405) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Summary Closes #2233 in iOS and old Arch, a callback on `toDataURL` method will only be called the second time of asking. Based on that [PR](https://github.com/software-mansion/react-native-svg/pull/2234) format `RNSVGSvgViewModule` file. ## Test Plan We can easily test that fix by running the `Test2233`, we have an example of the problem. ### What are the steps to reproduce (after prerequisites)? ## Compatibility | OS | Implemented | | ------- | :---------: | | iOS | ✅ | --- apple/RNSVGSvgViewModule.mm | 88 +++++++++++++++-------------- apps/test-examples/App.js | 1 + apps/test-examples/src/Test2233.tsx | 30 ++++++++++ 3 files changed, 76 insertions(+), 43 deletions(-) create mode 100644 apps/test-examples/src/Test2233.tsx diff --git a/apple/RNSVGSvgViewModule.mm b/apple/RNSVGSvgViewModule.mm index 3d869615..5b72f019 100644 --- a/apple/RNSVGSvgViewModule.mm +++ b/apple/RNSVGSvgViewModule.mm @@ -26,54 +26,47 @@ RCT_EXPORT_MODULE() callback:(RCTResponseSenderBlock)callback attempt:(int)attempt { - void (^block)(void) = ^{ #ifdef RCT_NEW_ARCH_ENABLED - [self.viewRegistry_DEPRECATED addUIBlock:^(RCTViewRegistry *viewRegistry) { - __kindof RNSVGPlatformView *view = [viewRegistry viewForReactTag:reactTag]; + [self.viewRegistry_DEPRECATED addUIBlock:^(RCTViewRegistry *viewRegistry) { + __kindof RNSVGPlatformView *view = [viewRegistry viewForReactTag:reactTag]; #else - [self.bridge.uiManager - addUIBlock:^(RCTUIManager *uiManager, NSDictionary *viewRegistry) { - __kindof RNSVGPlatformView *view = [uiManager viewForReactTag:reactTag]; + [self.bridge.uiManager + addUIBlock:^(RCTUIManager *uiManager, NSDictionary *viewRegistry) { + __kindof RNSVGPlatformView *view = [uiManager viewForReactTag:reactTag]; #endif // RCT_NEW_ARCH_ENABLED - NSString *b64; - if ([view isKindOfClass:[RNSVGSvgView class]]) { - RNSVGSvgView *svg = view; - if (options == nil) { - b64 = [svg getDataURLWithBounds:svg.boundingBox]; - } else { - id width = [options objectForKey:@"width"]; - id height = [options objectForKey:@"height"]; - if (![width isKindOfClass:NSNumber.class] || ![height isKindOfClass:NSNumber.class]) { - RCTLogError(@"Invalid width or height given to toDataURL"); - return; - } - NSNumber *w = width; - NSInteger wi = (NSInteger)[w intValue]; - NSNumber *h = height; - NSInteger hi = (NSInteger)[h intValue]; - - CGRect bounds = CGRectMake(0, 0, wi, hi); - b64 = [svg getDataURLWithBounds:bounds]; + NSString *b64; + if ([view isKindOfClass:[RNSVGSvgView class]]) { + RNSVGSvgView *svg = view; + if (options == nil) { + b64 = [svg getDataURLWithBounds:svg.boundingBox]; + } else { + id width = [options objectForKey:@"width"]; + id height = [options objectForKey:@"height"]; + if (![width isKindOfClass:NSNumber.class] || ![height isKindOfClass:NSNumber.class]) { + RCTLogError(@"Invalid width or height given to toDataURL"); + return; } - } else { - RCTLogError(@"Invalid svg returned from registry, expecting RNSVGSvgView, got: %@", view); - return; + NSNumber *w = width; + NSInteger wi = (NSInteger)[w intValue]; + NSNumber *h = height; + NSInteger hi = (NSInteger)[h intValue]; + + CGRect bounds = CGRectMake(0, 0, wi, hi); + b64 = [svg getDataURLWithBounds:bounds]; } - if (b64) { - callback(@[ b64 ]); - } else if (attempt < 1) { - [self toDataURL:reactTag options:options callback:callback attempt:(attempt + 1)]; - } else { - callback(@[]); - } - }]; - }; - if (self.bridge) { - dispatch_async(RCTGetUIManagerQueue(), block); - } else { - dispatch_async(dispatch_get_main_queue(), block); - } -} + } else { + RCTLogError(@"Invalid svg returned from registry, expecting RNSVGSvgView, got: %@", view); + return; + } + if (b64) { + callback(@[ b64 ]); + } else if (attempt < 1) { + [self toDataURL:reactTag options:options callback:callback attempt:(attempt + 1)]; + } else { + callback(@[]); + } + }]; +}; RCT_EXPORT_METHOD(toDataURL : (nonnull NSNumber *)reactTag options @@ -91,4 +84,13 @@ RCT_EXPORT_METHOD(toDataURL } #endif +- (dispatch_queue_t)methodQueue +{ + if (self.bridge) { + return RCTGetUIManagerQueue(); + } else { + return dispatch_get_main_queue(); + } +} + @end diff --git a/apps/test-examples/App.js b/apps/test-examples/App.js index 85142b70..e8615269 100644 --- a/apps/test-examples/App.js +++ b/apps/test-examples/App.js @@ -22,6 +22,7 @@ import Test2248 from './src/Test2248'; import Test2266 from './src/Test2266'; import Test2276 from './src/Test2276'; import Test2327 from './src/Test2327'; +import Test2233 from './src/Test2233'; import Test2366 from './src/Test2366'; import Test2397 from './src/Test2397'; diff --git a/apps/test-examples/src/Test2233.tsx b/apps/test-examples/src/Test2233.tsx new file mode 100644 index 00000000..4ba5dd14 --- /dev/null +++ b/apps/test-examples/src/Test2233.tsx @@ -0,0 +1,30 @@ +import * as React from 'react'; +import {Button, SafeAreaView, View} from 'react-native'; +import Svg, {Path} from 'react-native-svg'; + +const SvgLogoWelcome = () => { + const ref = React.useRef(null); + return ( + + + ); +}; + +export default function App() { + return ( + + + + ); +}