应用程序试图在 React Native Objective-C 扩展中的目标上呈现一个 nil 模态视图控制器
Posted
技术标签:
【中文标题】应用程序试图在 React Native Objective-C 扩展中的目标上呈现一个 nil 模态视图控制器【英文标题】:Application tried to present a nil modal view controller on target in React Native Objective-C extension 【发布时间】:2020-08-26 06:04:23 【问题描述】:我正在尝试将 ios 应用程序移植到 React Native。
在这个 iOS 应用程序中,需要完成的功能之一是将其与 PayPal 库集成(目前已弃用 - 我们希望在今年晚些时候离开它,但没有资源)。
我们对这个库所做的只是从 PayPal 获取一个唯一代码 - 这需要一个视图控制器弹出,接受客户端凭据并返回一个代码来授予访问权限。
我是非常Objective-C的新手。
到目前为止我已经得到了这个(注意:我没有包括所有的方法/属性,但可以包括任何缺失的):
COMPLETE PaypalSdk.h 和 PaypalSdk.m 现在位于底部
我基于这个库:
https://github.com/paypal/PayPal-iOS-SDK/blob/master/SampleApp/PayPal-iOS-SDK-Sample-App/ZZMainViewController.m
还有这个文档:
https://github.com/paypal/PayPal-iOS-SDK/blob/master/docs/profile_sharing_mobile.md
但是,当我尝试上面的操作时,我收到以下错误:
我应该如何解决这个问题?它似乎需要一个视图控制器,但我不完全确定如何在这种情况下从 React Native 启动一个。
我们试图获取的只是共享的个人资料信息。
这是堆栈跟踪之一:
callstack: (
0 CoreFoundation 0x00007fff23c7127e __exceptionPreprocess + 350
1 libobjc.A.dylib 0x00007fff513fbb20 objc_exception_throw + 48
2 UIKitCore 0x00007fff47a25b1a -[UIViewController _presentViewController:withAnimationController:completion:] + 5247
3 UIKitCore 0x00007fff47a2801b __63-[UIViewController _presentViewController:animated:completion:]_block_invoke + 98
4 UIKitCore 0x00007fff47a28533 -[UIViewController _performCoordinatedPresentOrDismiss:animated:] + 511
5 UIKitCore 0x00007fff47a27f79 -[UIViewController _presentViewController:animated:completion:] + 187
6 UIKitCore 0x00007fff47a281e0 -[UIViewController presentViewController:animated:completion:] + 150
7 myappname 0x000000010f92f8ac -[PaypalSdk getUserAuthorizationForProfileSharing] + 348
8 myappname 0x000000010f92fd99 -[PaypalSdk generateCode:] + 233
9 CoreFoundation 0x00007fff23c7820c __invoking___ + 140
10 CoreFoundation 0x00007fff23c753af -[NSInvocation invoke] + 319
11 CoreFoundation 0x00007fff23c75684 -[NSInvocation invokeWithTarget:] + 68
12 myappname 0x000000010f6e3902 -[RCTModuleMethod invokeWithBridge:module:arguments:] + 2658
13 myappname 0x000000010f6e7a37 _ZN8facebook5reactL11invokeInnerEP9RCTBridgeP13RCTModuleDatajRKN5folly7dynamicE + 791
14 myappname 0x000000010f6e7543 _ZZN8facebook5react15RCTNativeModule6invokeEjON5folly7dynamicEiENK3$_0clEv + 131
15 myappname 0x000000010f6e74b9 ___ZN8facebook5react15RCTNativeModule6invokeEjON5folly7dynamicEi_block_invoke + 25
16 libdispatch.dylib 0x0000000110caddd4 _dispatch_call_block_and_release + 12
17 libdispatch.dylib 0x0000000110caed48 _dispatch_client_callout + 8
18 libdispatch.dylib 0x0000000110cb55ef _dispatch_lane_serial_drain + 788
19 libdispatch.dylib 0x0000000110cb617f _dispatch_lane_invoke + 422
20 libdispatch.dylib 0x0000000110cc1a4e _dispatch_workloop_worker_thread + 719
21 libsystem_pthread.dylib 0x00007fff5246371b _pthread_wqthread + 290
22 libsystem_pthread.dylib 0x00007fff5246357b start_wqthread + 15
)
这是我完整的 PayPalSdk.m 文件:
#import <PayPal-iOS-SDK/PayPalMobile.h>
#import <PayPal-iOS-SDK/PayPalConfiguration.h>
#import <PayPal-iOS-SDK/PayPalOAuthScopes.h>
#import <PayPal-iOS-SDK/PayPalProfileSharingViewController.h>
#import <QuartzCore/QuartzCore.h>
#import "PaypalSdk.h"
@interface PaypalSdk ()
@property(nonatomic, strong, readwrite) IBOutlet UIButton *payNowButton;
@property(nonatomic, strong, readwrite) IBOutlet UIButton *payFutureButton;
@property(nonatomic, strong, readwrite) IBOutlet UIView *successView;
@property(nonatomic, strong, readwrite) PayPalConfiguration *payPalConfig;
@end
@implementation PaypalSdk
#define kPayPalEnvironment PayPalEnvironmentProduction
//int *REQUEST_CODE_PROFILE_SHARING = 3;
- (void)viewDidLoad
[super viewDidLoad];
self.title = @"Pinyada PayPal";
// Set up payPalConfig
self.payPalConfig = [[PayPalConfiguration alloc] init];
self.payPalConfig.acceptCreditCards = NO;
self.payPalConfig.merchantName = @"Pinyada PayPal";
self.payPalConfig.merchantPrivacyPolicyURL = [NSURL URLWithString:@"https://www.paypal.com/webapps/mpp/ua/privacy-full"];
self.payPalConfig.merchantUserAgreementURL = [NSURL URLWithString:@"https://www.paypal.com/webapps/mpp/ua/useragreement-full"];
NSLog(@"PayPal iOS SDK version: %@", [PayPalMobile libraryVersion]);
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
#warning "Enter your credentials"
[PayPalMobile initializeWithClientIdsForEnvironments:@PayPalEnvironmentProduction : @"PayPalProductionID",
PayPalEnvironmentSandbox : @"YOUR_CLIENT_ID_FOR_SANDBOX"];
return YES;
/*- (void)generateCode:()code
NSLog(@"Test");
*/
- (void)viewWillAppear:(BOOL)animated
[super viewWillAppear:animated];
// Start out working with the mock environment. When you are ready, switch to PayPalEnvironmentProduction.
[PayPalMobile preconnectWithEnvironment:PayPalEnvironmentProduction];
- (IBAction)getUserAuthorizationForProfileSharing:(id)sender
NSSet *scopeValues = [NSSet setWithArray:@[kPayPalOAuth2ScopeOpenId, kPayPalOAuth2ScopeEmail, kPayPalOAuth2ScopeAddress, kPayPalOAuth2ScopePhone]];
PayPalProfileSharingViewController *profileSharingPaymentViewController = [[PayPalProfileSharingViewController alloc] initWithScopeValues:scopeValues configuration:self.payPalConfig delegate:self];
[self presentViewController:profileSharingPaymentViewController animated:YES completion:nil];
- (IBAction)obtainConsent
// Choose whichever scope-values apply in your case. See `PayPalOAuthScopes.h` for a complete list of available scope-values.
NSSet *scopeValues = [NSSet setWithArray:@[kPayPalOAuth2ScopeOpenId, kPayPalOAuth2ScopeEmail, kPayPalOAuth2ScopeAddress, kPayPalOAuth2ScopePhone]];
PayPalProfileSharingViewController *psViewController;
NSLog(@"PS VIEW CONTROLLER");
NSLog(psViewController);
psViewController = [[PayPalProfileSharingViewController alloc] initWithScopeValues:scopeValues
configuration:self.payPalConfig
delegate:self];
// Access the root view controller
UIViewController *rootviewcontroller= [UIApplication sharedApplication].keyWindow.rootViewController;
// Present the PayPalProfileSharingViewController
[ rootviewcontroller presentViewController:psViewController animated:YES completion:nil];
- (void)userDidCancelPayPalProfileSharingViewController:(PayPalProfileSharingViewController *)profileSharingViewController
// User cancelled login. Dismiss the PayPalProfileSharingViewController, breathe deeply.
[self dismissViewControllerAnimated:YES completion:nil];
- (void)payPalProfileSharingViewController:(PayPalProfileSharingViewController *)profileSharingViewController
userDidLogInWithAuthorization:(NSDictionary *)profileSharingAuthorization
// The user has successfully logged into PayPal, and has consented to profile sharing.
NSLog(@"REACT NATIVE ENV test");
// Be sure to dismiss the PayPalProfileSharingViewController.
[self dismissViewControllerAnimated:YES completion:nil];
RCT_EXPORT_MODULE()
RCT_EXPORT_METHOD(generateCode: (RCTResponseSenderBlock)callback)
[PayPalMobile initializeWithClientIdsForEnvironments:@PayPalEnvironmentProduction : @"PayPalProductionID",
PayPalEnvironmentSandbox : @"YOUR_CLIENT_ID_FOR_SANDBOX"];
[self obtainConsent];
NSLog(@"REACT NATIVE ENV test");
//code = @"this is a test!";
// TODO: Implement some actually useful functionality
callback(@[[NSNull null], @"test"]);
@end
这是我完整的 PaypalSdk.h 文件:
#import "RCTBridgeModule.h"
#import "PayPalMobile.h"
@interface PaypalSdk : UIViewController <RCTBridgeModule, PayPalProfileSharingDelegate>
@property(nonatomic, strong, readwrite) NSString *environment;
@property(nonatomic, strong, readwrite) NSString *resultText;
@property(nonatomic, strong) UIWindow *window;
@property(nonatomic, strong) UIViewController *rootViewController;
@end
【问题讨论】:
您能分享红色模态中显示的完整堆栈跟踪吗? @CarlaCamargo 我有两个不同的堆栈跟踪,这取决于我是否进行了您建议的更改 - 您想要哪个堆栈跟踪,在您的建议之前还是之后? 【参考方案1】:所以你需要访问根视图控制器,然后调用presentViewController
。像下面这样的东西应该可以解决问题:
- (IBAction)obtainConsent
// Choose whichever scope-values apply in your case. See `PayPalOAuthScopes.h` for a complete list of available scope-values.
NSSet *scopeValues = [NSSet setWithArray:@[kPayPalOAuth2ScopeOpenId, kPayPalOAuth2ScopeEmail, kPayPalOAuth2ScopeAddress, kPayPalOAuth2ScopePhone]];
PayPalProfileSharingViewController *psViewController;
psViewController = [[PayPalProfileSharingViewController alloc] initWithScopeValues:scopeValues
configuration:self.payPalConfig
delegate:self];
// Access the root view controller
UIViewController *rootviewcontroller= [UIApplication sharedApplication].keyWindow.rootViewController;
// Present the PayPalProfileSharingViewController
[ rootviewcontroller presentViewController:psViewController animated:YES completion:nil];
我还没有尝试过,所以请检查并告诉我这是否有效。否则,找到一个可以呈现视图控制器的视图。
根据与 OP 的交互更新答案:
为此,必须使用 RCT 方法覆盖与视图相关的方法,并且需要在调用 generatecode RCT 方法之前调用它们。这与根视图控制器一起似乎可以解决问题。【讨论】:
不@manisg,用这个替换旧的getConsent时仍然有一个nil模式视图控制器 您在演示之前有一个 nil psViewController?还是在它之后? @CarlaCamargo 所以现在异常说,“应用程序试图在目标请勿使用该 SDK。它非常古老且已被弃用。
如果您需要原生 SDK 来处理使用 PayPal 的付款,您可以通过 Braintree 使用快速结账。它还需要您自己的网络服务:https://developer.paypal.com/docs/accept-payments/express-checkout/ec-braintree-sdk/get-started/
【讨论】:
我不需要 SDK 来处理付款。我需要用于共享配置文件的 SDK。我知道它已被弃用,正如我之前所说,我们希望摆脱它(如果我们能找到解决方案),但我们目前没有资源来摆脱它。从字面上看,我们使用它的只是个人资料共享,而 Braintree SDK 不支持。 我不知道共享个人资料信息是什么,但 PayPal 支持 API,您可以将其用于“与 PayPal 连接”等类型的事情 我不确定它与 iOS 的集成效果如何,但我们会在中期再次研究它。我们现在迫切需要在下个月内使用这个 SDK,并且想出一种替代方法是不可能的。很好,我们不应该使用这个 SDK,但是我们当前的实现已经在使用这个 SDK。我们正在从 Swift 应用程序转变为 RN 应用程序,然后一旦我们有一个适用于所有平台的统一工作应用程序,我们将寻求替换 PayPal 身份信息。 我仍然必须提醒您不要努力让一个已有 6 年历史的解决方案发挥作用。但如果你坚持走这条路,可能相关:github.com/paypal/PayPal-iOS-SDK/issues/390 再一次,我们已经在使用这个解决方案了。我们正在将当前应用程序迁移到新的多平台应用程序,之后我们将弃用此应用程序中进行个人资料共享的最新方式。 Connect with PayPal 仅限网站。我没有看到任何将它与移动应用程序集成的方法。我没有看到任何专门针对移动应用程序的解决方案,因此需要研究。与此同时,这是我们拥有的解决方案,我们的 API 将像现在一样被弃用以上是关于应用程序试图在 React Native Objective-C 扩展中的目标上呈现一个 nil 模态视图控制器的主要内容,如果未能解决你的问题,请参考以下文章
应用程序试图在 React Native Objective-C 扩展中的目标上呈现一个 nil 模态视图控制器
RNGoogleSignin 试图覆盖 RNGoogleSigninModule 错误
在 React Native WebView 中加载捆绑的静态资产