react-native-klarna-inapp-sdk 2.3.15 → 2.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/README.md +1 -0
  2. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/KlarnaMobileSDKPackage.java +2 -4
  3. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/checkout/KlarnaCheckoutViewEventSender.java +7 -2
  4. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/checkout/KlarnaCheckoutViewManager.java +51 -18
  5. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/common/WebViewResizeObserver.java +9 -4
  6. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/common/event/KlarnaEventHandlerEventsUtil.java +62 -3
  7. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/common/ui/ResizeObserverWrapperView.java +3 -2
  8. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/common/util/ArgumentsUtil.java +40 -0
  9. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/payments/PaymentViewWrapper.java +1 -1
  10. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/signin/KlarnaSignInData.java +15 -0
  11. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/signin/KlarnaSignInEventsMapper.java +40 -0
  12. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/signin/KlarnaSignInModuleImpl.java +124 -0
  13. package/android/src/newarch/java/com/klarna/mobile/sdk/reactnative/spec/RNKlarnaSignInModuleSpec.java +65 -0
  14. package/android/src/oldarch/java/com/klarna/mobile/sdk/reactnative/spec/RNKlarnaSignInModuleSpec.java +39 -0
  15. package/android/src/test/java/com/klarna/mobile/sdk/reactnative/KlarnaMobileSDKPackageTest.java +5 -4
  16. package/ios/Sources/KlarnaCheckoutViewManager.mm +32 -24
  17. package/ios/Sources/signIn/KlarnaSignInData.h +25 -0
  18. package/ios/Sources/signIn/KlarnaSignInData.mm +21 -0
  19. package/ios/Sources/signIn/KlarnaSignInEventsMapper.h +18 -0
  20. package/ios/Sources/signIn/KlarnaSignInEventsMapper.m +54 -0
  21. package/ios/Sources/signIn/KlarnaSignInModule.h +26 -0
  22. package/ios/Sources/signIn/KlarnaSignInModuleImpl.h +37 -0
  23. package/ios/Sources/signIn/KlarnaSignInModuleImpl.mm +244 -0
  24. package/ios/Sources/signIn/newarch/KlarnaSignInModule.mm +75 -0
  25. package/ios/Sources/signIn/oldarch/KlarnaSignInModule.mm +72 -0
  26. package/ios/Sources/view/KlarnaCheckoutViewWrapper.h +1 -3
  27. package/ios/Sources/view/newarch/KlarnaCheckoutViewWrapper.mm +53 -29
  28. package/ios/Sources/view/oldarch/KlarnaCheckoutViewWrapper.mm +58 -20
  29. package/lib/commonjs/KlarnaCheckoutView.js +16 -3
  30. package/lib/commonjs/KlarnaCheckoutView.js.map +1 -1
  31. package/lib/commonjs/KlarnaSignInSDK.js +80 -0
  32. package/lib/commonjs/KlarnaSignInSDK.js.map +1 -0
  33. package/lib/commonjs/index.js +11 -0
  34. package/lib/commonjs/index.js.map +1 -1
  35. package/lib/commonjs/specs/KlarnaCheckoutViewNativeComponent.js.map +1 -1
  36. package/lib/commonjs/specs/NativeKlarnaSignIn.js +10 -0
  37. package/lib/commonjs/specs/NativeKlarnaSignIn.js.map +1 -0
  38. package/lib/commonjs/types/common/KlarnaEnvironment.js +13 -0
  39. package/lib/commonjs/types/common/KlarnaEnvironment.js.map +1 -0
  40. package/lib/commonjs/types/common/KlarnaRegion.js +14 -0
  41. package/lib/commonjs/types/common/KlarnaRegion.js.map +1 -0
  42. package/lib/module/KlarnaCheckoutView.js +16 -3
  43. package/lib/module/KlarnaCheckoutView.js.map +1 -1
  44. package/lib/module/KlarnaSignInSDK.js +72 -0
  45. package/lib/module/KlarnaSignInSDK.js.map +1 -0
  46. package/lib/module/index.js +1 -0
  47. package/lib/module/index.js.map +1 -1
  48. package/lib/module/specs/KlarnaCheckoutViewNativeComponent.js.map +1 -1
  49. package/lib/module/specs/NativeKlarnaSignIn.js +3 -0
  50. package/lib/module/specs/NativeKlarnaSignIn.js.map +1 -0
  51. package/lib/module/types/common/KlarnaEnvironment.js +6 -0
  52. package/lib/module/types/common/KlarnaEnvironment.js.map +1 -0
  53. package/lib/module/types/common/KlarnaRegion.js +7 -0
  54. package/lib/module/types/common/KlarnaRegion.js.map +1 -0
  55. package/lib/typescript/KlarnaCheckoutView.d.ts +2 -0
  56. package/lib/typescript/KlarnaCheckoutView.d.ts.map +1 -1
  57. package/lib/typescript/KlarnaSignInSDK.d.ts +19 -0
  58. package/lib/typescript/KlarnaSignInSDK.d.ts.map +1 -0
  59. package/lib/typescript/index.d.ts +1 -0
  60. package/lib/typescript/index.d.ts.map +1 -1
  61. package/lib/typescript/specs/KlarnaCheckoutViewNativeComponent.d.ts +1 -0
  62. package/lib/typescript/specs/KlarnaCheckoutViewNativeComponent.d.ts.map +1 -1
  63. package/lib/typescript/specs/NativeKlarnaSignIn.d.ts +10 -0
  64. package/lib/typescript/specs/NativeKlarnaSignIn.d.ts.map +1 -0
  65. package/lib/typescript/types/common/KlarnaEnvironment.d.ts +5 -0
  66. package/lib/typescript/types/common/KlarnaEnvironment.d.ts.map +1 -0
  67. package/lib/typescript/types/common/KlarnaMobileSDKError.d.ts +4 -0
  68. package/lib/typescript/types/common/KlarnaMobileSDKError.d.ts.map +1 -1
  69. package/lib/typescript/types/common/KlarnaProductEvent.d.ts +1 -0
  70. package/lib/typescript/types/common/KlarnaProductEvent.d.ts.map +1 -1
  71. package/lib/typescript/types/common/KlarnaRegion.d.ts +6 -0
  72. package/lib/typescript/types/common/KlarnaRegion.d.ts.map +1 -0
  73. package/package.json +1 -1
  74. package/react-native-klarna-inapp-sdk.podspec +1 -1
  75. package/src/KlarnaCheckoutView.tsx +16 -3
  76. package/src/KlarnaSignInSDK.tsx +122 -0
  77. package/src/index.tsx +1 -0
  78. package/src/specs/KlarnaCheckoutViewNativeComponent.ts +1 -0
  79. package/src/specs/NativeKlarnaSignIn.ts +25 -0
  80. package/src/types/common/KlarnaEnvironment.ts +4 -0
  81. package/src/types/common/KlarnaMobileSDKError.ts +2 -0
  82. package/src/types/common/KlarnaProductEvent.ts +1 -0
  83. package/src/types/common/KlarnaRegion.ts +5 -0
@@ -0,0 +1,39 @@
1
+ package com.klarna.mobile.sdk.reactnative.spec;
2
+
3
+ import androidx.annotation.NonNull;
4
+
5
+ import com.facebook.react.bridge.Promise;
6
+ import com.facebook.react.bridge.ReactApplicationContext;
7
+ import com.facebook.react.bridge.ReactContextBaseJavaModule;
8
+ import com.facebook.react.bridge.ReactMethod;
9
+ import com.klarna.mobile.sdk.reactnative.signin.KlarnaSignInModuleImpl;
10
+
11
+ public class RNKlarnaSignInModuleSpec extends ReactContextBaseJavaModule {
12
+ private KlarnaSignInModuleImpl module;
13
+
14
+ public RNKlarnaSignInModuleSpec(ReactApplicationContext reactContext) {
15
+ super(reactContext);
16
+ this.module = new KlarnaSignInModuleImpl(reactContext);
17
+ }
18
+
19
+ @NonNull
20
+ @Override
21
+ public String getName() {
22
+ return KlarnaSignInModuleImpl.NAME;
23
+ }
24
+
25
+ @ReactMethod(isBlockingSynchronousMethod = false)
26
+ public void init(String instanceId, String environment, String region, String returnUrl, Promise promise) {
27
+ module.init(instanceId, environment, region, returnUrl, promise);
28
+ }
29
+
30
+ @ReactMethod(isBlockingSynchronousMethod = false)
31
+ public void dispose(String instanceId, Promise promise) {
32
+ module.dispose(instanceId, promise);
33
+ }
34
+
35
+ @ReactMethod(isBlockingSynchronousMethod = false)
36
+ public void signIn(String instanceId, String clientId, String scope, String market, String locale, String tokenizationId, Promise promise) {
37
+ module.signIn(instanceId, clientId, scope, market, locale, tokenizationId, promise);
38
+ }
39
+ }
@@ -10,6 +10,7 @@ import com.facebook.react.uimanager.ViewManager;
10
10
  import com.klarna.mobile.sdk.reactnative.KlarnaMobileSDKPackage;
11
11
  import com.klarna.mobile.sdk.reactnative.checkout.KlarnaCheckoutViewManager;
12
12
  import com.klarna.mobile.sdk.reactnative.payments.KlarnaPaymentViewManager;
13
+ import com.klarna.mobile.sdk.reactnative.spec.RNKlarnaSignInModuleSpec;
13
14
  import com.klarna.mobile.sdk.reactnative.standalonewebview.KlarnaStandaloneWebViewManager;
14
15
 
15
16
  import org.junit.Assert;
@@ -34,10 +35,10 @@ public class KlarnaMobileSDKPackageTest {
34
35
 
35
36
  @Test
36
37
  public void testCreateNativeModules() {
37
- KlarnaMobileSDKPackage paymentViewPackage = new KlarnaMobileSDKPackage();
38
- List<NativeModule> nativeModules = paymentViewPackage.createNativeModules(reactContext);
39
- Assert.assertNotNull(nativeModules);
40
- Assert.assertTrue(nativeModules.isEmpty());
38
+ KlarnaMobileSDKPackage mobilePackage = new KlarnaMobileSDKPackage();
39
+ List<NativeModule> nativeModules = mobilePackage.createNativeModules(reactContext);
40
+ Assert.assertEquals(1, nativeModules.size());
41
+ Assert.assertTrue(nativeModules.get(0) instanceof RNKlarnaSignInModuleSpec);
41
42
  }
42
43
 
43
44
  @Test
@@ -1,20 +1,21 @@
1
- #import "KlarnaCheckoutViewManager.h"
2
-
3
1
  #import <React/RCTUIManager.h>
4
2
  #import <React/RCTLog.h>
5
-
3
+ #import "KlarnaCheckoutViewManager.h"
6
4
  #import "view/KlarnaCheckoutViewWrapper.h"
7
5
 
8
6
  @implementation KlarnaCheckoutViewManager
9
7
 
10
8
  RCT_EXPORT_MODULE(RNKlarnaCheckoutView)
11
9
 
12
- #pragma mark - View
10
+ #pragma mark - View Properties
13
11
 
14
12
  RCT_EXPORT_VIEW_PROPERTY(returnUrl, NSString)
15
13
  RCT_EXPORT_VIEW_PROPERTY(onEvent, RCTDirectEventBlock)
16
14
  RCT_EXPORT_VIEW_PROPERTY(onError, RCTDirectEventBlock)
17
15
  RCT_EXPORT_VIEW_PROPERTY(onResized, RCTDirectEventBlock)
16
+ RCT_EXPORT_VIEW_PROPERTY(onCheckoutViewReady, RCTDirectEventBlock)
17
+
18
+ #pragma mark - View Creation
18
19
 
19
20
  - (UIView *)view
20
21
  {
@@ -23,39 +24,46 @@ RCT_EXPORT_VIEW_PROPERTY(onResized, RCTDirectEventBlock)
23
24
  return wrapper;
24
25
  }
25
26
 
26
- #pragma mark - Exported Methods
27
+ #pragma mark - Exported Methods to React Native
27
28
 
28
- RCT_EXPORT_METHOD(setSnippet:(nonnull NSNumber*)reactTag snippet:(NSString*)snippet) {
29
- [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *,UIView *> *viewRegistry) {
30
- KlarnaCheckoutViewWrapper* view = (KlarnaCheckoutViewWrapper*) viewRegistry[reactTag];
31
- if (!view || ![view isKindOfClass:KlarnaCheckoutViewWrapper.class]) {
32
- RCTLogError(@"Can't find KlarnaCheckoutViewWrapper with tag #%@", reactTag);
33
- return;
29
+ RCT_EXPORT_METHOD(setSnippet:(nonnull NSNumber *)reactTag snippet:(NSString *)snippet)
30
+ {
31
+ [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
32
+ KlarnaCheckoutViewWrapper *view = [self checkoutViewWrapperForTag:reactTag fromRegistry:viewRegistry];
33
+ if (view) {
34
+ [view setSnippet:snippet];
34
35
  }
35
- [view setSnippet:snippet];
36
36
  }];
37
37
  }
38
38
 
39
- RCT_EXPORT_METHOD(suspend:(nonnull NSNumber*)reactTag) {
39
+ RCT_EXPORT_METHOD(suspend:(nonnull NSNumber *)reactTag) {
40
40
  [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *,UIView *> *viewRegistry) {
41
- KlarnaCheckoutViewWrapper* view = (KlarnaCheckoutViewWrapper*) viewRegistry[reactTag];
42
- if (!view || ![view isKindOfClass:KlarnaCheckoutViewWrapper.class]) {
43
- RCTLogError(@"Can't find KlarnaCheckoutViewWrapper with tag #%@", reactTag);
44
- return;
41
+ KlarnaCheckoutViewWrapper *view = [self checkoutViewWrapperForTag:reactTag fromRegistry:viewRegistry];
42
+ if (view) {
43
+ [view suspend];
45
44
  }
46
- [view suspend];
47
45
  }];
48
46
  }
49
47
 
50
- RCT_EXPORT_METHOD(resume:(nonnull NSNumber*)reactTag) {
48
+ RCT_EXPORT_METHOD(resume:(nonnull NSNumber *)reactTag) {
51
49
  [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *,UIView *> *viewRegistry) {
52
- KlarnaCheckoutViewWrapper* view = (KlarnaCheckoutViewWrapper*) viewRegistry[reactTag];
53
- if (!view || ![view isKindOfClass:KlarnaCheckoutViewWrapper.class]) {
54
- RCTLogError(@"Can't find KlarnaCheckoutViewWrapper with tag #%@", reactTag);
55
- return;
50
+ KlarnaCheckoutViewWrapper *view = [self checkoutViewWrapperForTag:reactTag fromRegistry:viewRegistry];
51
+ if (view) {
52
+ [view resume];
56
53
  }
57
- [view resume];
58
54
  }];
59
55
  }
60
56
 
57
+ #pragma mark - Private Helper Methods
58
+
59
+ - (KlarnaCheckoutViewWrapper *)checkoutViewWrapperForTag:(NSNumber *)reactTag fromRegistry:(NSDictionary<NSNumber *, UIView *> *)viewRegistry
60
+ {
61
+ UIView *view = viewRegistry[reactTag];
62
+ if (!view || ![view isKindOfClass:[KlarnaCheckoutViewWrapper class]]) {
63
+ RCTLogError(@"Can't find KlarnaCheckoutViewWrapper with tag #%@", reactTag);
64
+ return nil;
65
+ }
66
+ return (KlarnaCheckoutViewWrapper *)view;
67
+ }
68
+
61
69
  @end
@@ -0,0 +1,25 @@
1
+ //
2
+ // KlarnaSignInData.h
3
+ // react-native-klarna-inapp-sdk
4
+ //
5
+ // Created by Jorge Palacio on 2025-03-12.
6
+ //
7
+
8
+ #import <Foundation/Foundation.h>
9
+ #import "KlarnaMobileSDK/KlarnaMobileSDK-Swift.h"
10
+ #import <React/RCTBridgeModule.h>
11
+
12
+ NS_ASSUME_NONNULL_BEGIN
13
+
14
+ @interface KlarnaSignInData : NSObject
15
+
16
+ @property (nonatomic, strong) NSString *instanceID;
17
+ @property (nonatomic, strong) KlarnaSignInSDK *sdkInstance API_AVAILABLE(ios(13.0));
18
+ @property (nonatomic, copy) RCTPromiseResolveBlock resolver;
19
+ @property (nonatomic, copy) RCTPromiseRejectBlock rejecter;
20
+
21
+ -(instancetype)initWith:(NSString *)instanceID sdkInstance:(KlarnaSignInSDK *)sdkInstance;
22
+
23
+ @end
24
+
25
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,21 @@
1
+ //
2
+ // KlarnaSignInData.m
3
+ // react-native-klarna-inapp-sdk
4
+ //
5
+ // Created by Jorge Palacio on 2025-03-12.
6
+ //
7
+
8
+ #import "KlarnaSignInData.h"
9
+
10
+ @implementation KlarnaSignInData
11
+
12
+ -(instancetype)initWith:(NSString *)instanceID sdkInstance:(KlarnaSignInSDK *)sdkInstance {
13
+ self = [super init];
14
+ if (self) {
15
+ _instanceID = instanceID;
16
+ _sdkInstance = sdkInstance;
17
+ }
18
+ return self;
19
+ }
20
+
21
+ @end
@@ -0,0 +1,18 @@
1
+ //
2
+ // KlarnaSignInErrorsMapper.h
3
+ // react-native-klarna-inapp-sdk
4
+ //
5
+ // Created by Jorge Palacio on 2025-05-13.
6
+ //
7
+
8
+ #import <Foundation/Foundation.h>
9
+
10
+ NS_ASSUME_NONNULL_BEGIN
11
+
12
+ @interface KlarnaSignInEventsMapper : NSObject
13
+ +(NSString *)mapSignInErrorName:(NSString *)errorName;
14
+ +(NSString *)mapSignInEventName:(NSString *)eventName;
15
+ +(NSString *)mapSignInParamName:(NSString *)paramName;
16
+ @end
17
+
18
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,54 @@
1
+ //
2
+ // KlarnaSignInErrorsMapper.m
3
+ // react-native-klarna-inapp-sdk
4
+ //
5
+ // Created by Jorge Palacio on 2025-05-13.
6
+ //
7
+
8
+ #import "KlarnaSignInEventsMapper.h"
9
+
10
+ @implementation KlarnaSignInEventsMapper
11
+ +(NSString *)mapSignInErrorName:(NSString *)errorName {
12
+ NSDictionary *signInErrorsMap = @{
13
+ @"klarnaInvalidReturnURLError": @"KlarnaSignInInvalidReturnURL",
14
+ @"klarnaSignInAlreadyInProgress": @"KlarnaSignInAlreadyInProgress",
15
+ @"klarnaSignInAuthorizationFailed": @"KlarnaSignInAuthorizationFailed",
16
+ @"klarnaSignInInvalidClientID": @"KlarnaSignInInvalidClientID",
17
+ @"klarnaSignInInvalidMarket": @"KlarnaSignInInvalidMarket",
18
+ @"klarnaSignInInvalidPresentationContext": @"KlarnaSignInInvalidPresentationContext",
19
+ @"klarnaSignInInvalidScope": @"KlarnaSignInInvalidScope",
20
+ @"klarnaSignInMissingTokenizationDelegate": @"KlarnaSignInMissingTokenizationId",
21
+ };
22
+ NSString *mappedError = signInErrorsMap[errorName];
23
+ if (mappedError) {
24
+ return mappedError;
25
+ } else {
26
+ return errorName;
27
+ }
28
+ }
29
+
30
+ +(NSString *)mapSignInEventName:(NSString *)eventName {
31
+ NSDictionary *signInEventsMap = @{
32
+ @"klarnaToken": @"KlarnaSignInToken",
33
+ @"klarnaSignInUserCancelled": @"KlarnaSignInUserCancelled"
34
+ };
35
+ NSString *mappedEvent = signInEventsMap[eventName];
36
+ if (mappedEvent) {
37
+ return mappedEvent;
38
+ } else {
39
+ return eventName;
40
+ }
41
+ }
42
+
43
+ +(NSString *)mapSignInParamName:(NSString *)paramName {
44
+ NSDictionary *signInParamsMap = @{
45
+ @"klarnaToken": @"KlarnaSignInToken"
46
+ };
47
+ NSString *mappedParam = signInParamsMap[paramName];
48
+ if (mappedParam) {
49
+ return mappedParam;
50
+ } else {
51
+ return paramName;
52
+ }
53
+ }
54
+ @end
@@ -0,0 +1,26 @@
1
+ //
2
+ // KlarnaSignInSDK.h
3
+ // RNKlarnaMobileSDK
4
+ //
5
+ // Created by Jorge Palacio on 2025-02-20.
6
+ // Copyright © 2025 Facebook. All rights reserved.
7
+ //
8
+
9
+ #import <Foundation/Foundation.h>
10
+ #import <React/RCTBridgeModule.h>
11
+ #import <RNKlarnaMobileSDK/RNKlarnaMobileSDK.h>
12
+
13
+ NS_ASSUME_NONNULL_BEGIN
14
+
15
+ #ifdef RCT_NEW_ARCH_ENABLED
16
+ @interface KlarnaSignInModule: NSObject<NativeKlarnaSignInSpec>
17
+
18
+ #else
19
+
20
+ @interface KlarnaSignInModule: NSObject<RCTBridgeModule>
21
+
22
+ #endif
23
+
24
+ @end
25
+
26
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,37 @@
1
+ //
2
+ // KlarnaSignInEventsHandler.h
3
+ // react-native-klarna-inapp-sdk
4
+ //
5
+ // Created by Jorge Palacio on 2025-02-26.
6
+ //
7
+
8
+ #import <Foundation/Foundation.h>
9
+ #import <React/RCTBridgeModule.h>
10
+
11
+ NS_ASSUME_NONNULL_BEGIN
12
+
13
+ @interface KlarnaSignInModuleImp: NSObject
14
+
15
+ - (void)dispose:(NSString *)instanceId
16
+ resolver:(RCTPromiseResolveBlock)resolve
17
+ rejecter:(RCTPromiseRejectBlock)reject;
18
+
19
+ -(void)initWith:(NSString *)instanceId
20
+ environment: (NSString *)environment
21
+ region: (NSString *)region
22
+ returnUrl: (NSString *) returnUrl
23
+ resolver:(RCTPromiseResolveBlock)resolve
24
+ rejecter:(RCTPromiseRejectBlock)reject;
25
+
26
+ -(void)signInWith:(NSString *)instanceId
27
+ clientId:(NSString *)clientId
28
+ scope:(NSString *)scope
29
+ market:(NSString *)market
30
+ locale:(NSString *)locale
31
+ tokenizationId:(NSString *)tokenizationId
32
+ resolver:(RCTPromiseResolveBlock)resolve
33
+ rejecter:(RCTPromiseRejectBlock)reject;
34
+
35
+ @end
36
+
37
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,244 @@
1
+ //
2
+ // KlarnaSignInEventsHandler.m
3
+ // react-native-klarna-inapp-sdk
4
+ //
5
+ // Created by Jorge Palacio on 2025-02-26.
6
+ //
7
+
8
+ #import "KlarnaSignInModuleImpl.h"
9
+ #import "../common/RNMobileSDKUtils.h"
10
+ #import <AuthenticationServices/AuthenticationServices.h>
11
+ #import "KlarnaMobileSDK/KlarnaMobileSDK-Swift.h"
12
+ #import <React/RCTLog.h>
13
+ #import "KlarnaSignInData.h"
14
+ #import "KlarnaSignInEventsMapper.h"
15
+
16
+ @interface KlarnaSignInModuleImp()<KlarnaEventHandler, ASWebAuthenticationPresentationContextProviding>
17
+
18
+ @property (nonatomic, strong) NSMutableDictionary<NSString *, KlarnaSignInData *> *signInSDKs;
19
+
20
+ - (KlarnaEnvironment *)environmentFrom: (NSString *)value;
21
+ - (KlarnaRegion *)regionFrom: (NSString *)value;
22
+ - (void)rejectWithInvalidiOSVersionSupported:(RCTPromiseRejectBlock) rejectBlock;
23
+ - (KlarnaSignInData *)getInstanceFromComponent: (id <KlarnaComponent> _Nonnull)component;
24
+
25
+ @end
26
+
27
+ @implementation KlarnaSignInModuleImp
28
+
29
+ - (id)init {
30
+ self = [super init];
31
+ _signInSDKs = [NSMutableDictionary new];
32
+ return self;
33
+ }
34
+
35
+ - (KlarnaEnvironment *)environmentFrom: (NSString *)value {
36
+ KlarnaEnvironment *env = KlarnaEnvironment.production;
37
+ if ([value isEqualToString:@"playground"]) {
38
+ env = KlarnaEnvironment.playground;
39
+ }
40
+ if ([value isEqualToString:@"staging"]) {
41
+ env = KlarnaEnvironment.staging;
42
+ }
43
+ if ([value isEqualToString:@"production"]) {
44
+ env = KlarnaEnvironment.production;
45
+ }
46
+
47
+ return env;
48
+ }
49
+
50
+ - (KlarnaRegion *)regionFrom: (NSString *)value {
51
+ KlarnaRegion *reg = KlarnaRegion.eu;
52
+ if ([value isEqualToString:@"eu"]) {
53
+ reg = KlarnaRegion.eu;
54
+ }
55
+
56
+ if ([value isEqualToString:@"na"]) {
57
+ reg = KlarnaRegion.na;
58
+ }
59
+
60
+ if ([value isEqualToString:@"oc"]) {
61
+ reg = KlarnaRegion.oc;
62
+ }
63
+
64
+ return reg;
65
+ }
66
+
67
+ - (KlarnaSignInData *)getInstanceFromComponent:(id<KlarnaComponent>)component {
68
+ for (NSString *key in _signInSDKs) {
69
+ KlarnaSignInData *data = _signInSDKs[key];
70
+ if (data.sdkInstance == component) {
71
+ return data;
72
+ }
73
+ }
74
+ return nil;
75
+ }
76
+
77
+ // MARK: - Module public Methods
78
+
79
+ - (void)dispose:(NSString *)instanceId
80
+ resolver:(RCTPromiseResolveBlock)resolve
81
+ rejecter:(RCTPromiseRejectBlock)reject {
82
+ KlarnaSignInData *signInData = _signInSDKs[instanceId];
83
+ if (signInData != nil) {
84
+ [_signInSDKs removeObjectForKey:instanceId];
85
+ resolve(nil);
86
+ }
87
+ }
88
+
89
+ - (void)initWith:(NSString *)instanceId
90
+ environment: (NSString *)environment
91
+ region: (NSString *)region
92
+ returnUrl: (NSString *)returnUrl
93
+ resolver:(RCTPromiseResolveBlock)resolve
94
+ rejecter:(RCTPromiseRejectBlock)reject {
95
+ KlarnaEnvironment * env = [self environmentFrom: environment];
96
+ KlarnaRegion * reg = [self regionFrom: region];
97
+ NSURL *url = [NSURL URLWithString: returnUrl];
98
+ if (url != nil && url.scheme != nil) {
99
+ if (@available(iOS 13.0, *)) {
100
+ KlarnaSignInSDK *signInInstance = [[KlarnaSignInSDK alloc] initWithEnvironment: env
101
+ region: reg
102
+ returnUrl: url
103
+ eventHandler: self];
104
+ KlarnaSignInData *data = [[KlarnaSignInData alloc] initWith: instanceId sdkInstance: signInInstance];
105
+ [_signInSDKs setObject: data forKey: instanceId];
106
+ resolve(nil);
107
+ } else {
108
+ [self rejectWithInvalidiOSVersionSupported: reject];
109
+ }
110
+ } else {
111
+ [self rejectWithInvalidURL: reject];
112
+ }
113
+ }
114
+
115
+ - (void)signInWith:(NSString *)instanceId
116
+ clientId:(NSString *)clientId
117
+ scope:(NSString *)scope
118
+ market:(NSString *)market
119
+ locale:(NSString *)locale
120
+ tokenizationId:(NSString *)tokenizationId
121
+ resolver:(RCTPromiseResolveBlock)resolve
122
+ rejecter:(RCTPromiseRejectBlock)reject {
123
+ if (@available(iOS 13.0, *)) {
124
+ KlarnaSignInData *signInData = [_signInSDKs objectForKey: instanceId];
125
+ if (signInData == nil) {
126
+ RCTLog(@"No instance found for the given instanceId");
127
+ reject(@"RNKlarnaSignIn", @"No instance found to initiate signIn, Init function must be called prior to this one.", nil);
128
+ } else {
129
+ signInData.resolver = resolve;
130
+ signInData.rejecter = reject;
131
+ [signInData.sdkInstance signInClientId: clientId
132
+ scope: scope
133
+ market: market
134
+ locale: locale
135
+ tokenizationId: tokenizationId
136
+ presentationContext: self];
137
+ }
138
+ } else {
139
+ [self rejectWithInvalidiOSVersionSupported: reject];
140
+ }
141
+ }
142
+
143
+ - (void)rejectWithInvalidiOSVersionSupported:(RCTPromiseRejectBlock) rejectBlock {
144
+ NSString *msg = @"KlarnaSignIn is supported from iOS version 13.0";
145
+ rejectBlock(@"RNKlarnaSignIn", msg, nil);
146
+ }
147
+
148
+ - (void)rejectWithInvalidURL:(RCTPromiseRejectBlock) rejectBlock {
149
+ NSString *msg = @"Invalid or null return URL.";
150
+ NSError *errorEvent = [NSError errorWithDomain:@"com.klarnamobilesdk" code: 0001 userInfo: @{
151
+ @"name": @"KlarnaSignInInvalidReturnUrl",
152
+ @"message": msg,
153
+ @"isFatal": @"true"
154
+ }];
155
+ rejectBlock(@"", msg, errorEvent);
156
+ }
157
+
158
+ // MARK: - KlarnaEventHandler Methods
159
+
160
+ - (void)klarnaComponent:(id <KlarnaComponent> _Nonnull)klarnaComponent dispatchedEvent:(KlarnaProductEvent * _Nonnull)event {
161
+ KlarnaSignInData *signInData = [self getInstanceFromComponent: klarnaComponent];
162
+ if (signInData == nil) {
163
+ RCTLog(@"No instance found for the given component");
164
+ return;
165
+ }
166
+ if (signInData.resolver == nil) {
167
+ RCTLog(@"Missing 'resolver' callback prop.");
168
+ return;
169
+ }
170
+ NSMutableDictionary<NSString *, id> *resolvedEvent = [NSMutableDictionary dictionaryWithDictionary: @{
171
+ @"action": [KlarnaSignInEventsMapper mapSignInEventName: event.action],
172
+ @"sessionId": event.sessionId,
173
+ }];
174
+ NSMutableDictionary *updatedParams = [NSMutableDictionary new];
175
+ [[event getParams] enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSString * _Nonnull obj, BOOL * _Nonnull stop) {
176
+ NSString *updatedKey = [KlarnaSignInEventsMapper mapSignInParamName: key];
177
+ [updatedParams setValue: obj forKey: updatedKey];
178
+ }];
179
+ if ([updatedParams count] > 0) {
180
+ [resolvedEvent setValue: updatedParams forKey: @"params"];
181
+ }
182
+ signInData.resolver(resolvedEvent);
183
+ }
184
+
185
+ - (void)klarnaComponent:(id <KlarnaComponent> _Nonnull)klarnaComponent encounteredError:(KlarnaError * _Nonnull)error {
186
+ if (!error.isFatal) {
187
+ NSArray *allowedNonFatalErrors = @[@"KlarnaSignInAlreadyInProgress", @"KlarnaSignInAuthorizationFailed"];
188
+ if (![allowedNonFatalErrors containsObject: error.name]) {
189
+ return;
190
+ }
191
+ }
192
+ KlarnaSignInData *signInData = [self getInstanceFromComponent: klarnaComponent];
193
+ if (signInData == nil) {
194
+ RCTLog(@"No instance found for the given component");
195
+ } else {
196
+ if (signInData.rejecter == nil) {
197
+ RCTLog(@"Missing 'rejecter' callback prop.");
198
+ } else {
199
+ NSMutableDictionary<NSString *, id> *infoDict = [NSMutableDictionary dictionaryWithDictionary: @{
200
+ @"name": [KlarnaSignInEventsMapper mapSignInErrorName: error.name],
201
+ @"message": error.message,
202
+ @"isFatal": error.isFatal ? @"true" : @"false",
203
+ @"sessionId": error.sessionId,
204
+ }];
205
+ NSDictionary *params = [error getParams];
206
+ if ([params count] > 0) {
207
+ [infoDict setValue: params forKey: @"params"];
208
+ }
209
+ NSError *errorEvent = [NSError errorWithDomain:@"com.klarnamobilesdk" code: 0001 userInfo: infoDict];
210
+ signInData.rejecter(@"", error.message, errorEvent);
211
+ }
212
+ }
213
+ }
214
+
215
+ // MARK: - ASWebAuthenticationPresentationContextProviding
216
+
217
+ - (ASPresentationAnchor)presentationAnchorForWebAuthenticationSession:(ASWebAuthenticationSession *)session {
218
+ UIWindowScene *windowScene = (UIWindowScene *)[[[UIApplication sharedApplication].connectedScenes objectsPassingTest:^BOOL(UIScene * _Nonnull obj, BOOL * _Nonnull stop) {
219
+ if(obj.activationState == UISceneActivationStateForegroundActive) {
220
+ *stop = YES; // Stop after finding the first match
221
+ return YES;
222
+ }
223
+ return NO;
224
+ }] allObjects].firstObject;
225
+
226
+ if (windowScene != nil) {
227
+ if (@available(iOS 15.0, *)) {
228
+ return windowScene.keyWindow;
229
+ } else {
230
+ UIWindow *currentTopWindow = windowScene.windows.firstObject;
231
+ if (currentTopWindow != nil) {
232
+ return currentTopWindow;
233
+ }
234
+ }
235
+
236
+ return [[UIWindow alloc] initWithWindowScene: windowScene];
237
+ }
238
+
239
+ // This Shouldn't execute app crashes!!!
240
+ // Windows can't be created in a bg thread. Hence the crash.
241
+ return nil;
242
+ }
243
+
244
+ @end
@@ -0,0 +1,75 @@
1
+ //
2
+ // KlarnaSignInSDK.m
3
+ // RNKlarnaMobileSDK
4
+ //
5
+ // Created by Jorge Palacio on 2025-02-20.
6
+ // Copyright © 2025 Facebook. All rights reserved.
7
+ //
8
+ #ifdef RCT_NEW_ARCH_ENABLED
9
+
10
+ #import "KlarnaSignInModule.h"
11
+ #import "KlarnaSignInModuleImpl.h"
12
+
13
+ @interface KlarnaSignInModule()
14
+
15
+ @property (strong, nonatomic) KlarnaSignInModuleImp *signInModule;
16
+
17
+ @end
18
+
19
+ @implementation KlarnaSignInModule
20
+
21
+ RCT_EXPORT_MODULE(RNKlarnaSignIn);
22
+
23
+ - (id)init {
24
+ self = [super init];
25
+ _signInModule = [KlarnaSignInModuleImp new];
26
+ return self;
27
+ }
28
+
29
+ - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const facebook::react::ObjCTurboModule::InitParams &)params {
30
+ return std::make_shared<facebook::react::NativeKlarnaSignInSpecJSI>(params);
31
+ }
32
+
33
+ - (void)dispose:(NSString *)instanceId
34
+ resolve:(RCTPromiseResolveBlock)resolve
35
+ reject:(RCTPromiseRejectBlock)reject {
36
+ [self.signInModule dispose:instanceId
37
+ resolver:resolve
38
+ rejecter:reject];
39
+ }
40
+
41
+ - (void)init:(NSString *)instanceId
42
+ environment:(NSString *)environment
43
+ region:(NSString *)region
44
+ returnUrl:(NSString *)returnUrl
45
+ resolve:(RCTPromiseResolveBlock)resolve
46
+ reject:(RCTPromiseRejectBlock)reject {
47
+ [self.signInModule initWith: instanceId
48
+ environment: environment
49
+ region: region
50
+ returnUrl: returnUrl
51
+ resolver: resolve
52
+ rejecter: reject];
53
+ }
54
+
55
+ - (void)signIn:(NSString *)instanceId
56
+ clientId:(NSString *)clientId
57
+ scope:(NSString *)scope
58
+ market:(NSString *)market
59
+ locale:(NSString *)locale
60
+ tokenizationId:(NSString *)tokenizationId
61
+ resolve:(RCTPromiseResolveBlock)resolve
62
+ reject:(RCTPromiseRejectBlock)reject {
63
+ [self.signInModule signInWith: instanceId
64
+ clientId: clientId
65
+ scope: scope
66
+ market: market
67
+ locale: locale
68
+ tokenizationId: tokenizationId
69
+ resolver: resolve
70
+ rejecter: reject];
71
+ }
72
+
73
+ @end
74
+
75
+ #endif