react-native-klarna-inapp-sdk 2.2.5 → 2.3.0
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.
- package/README.md +3 -2
- package/android/build.gradle +10 -10
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/KlarnaMobileSDKPackage.java +3 -1
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/checkout/KlarnaCheckoutViewEventHandler.java +32 -0
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/checkout/KlarnaCheckoutViewEventSender.java +56 -0
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/checkout/KlarnaCheckoutViewManager.java +147 -0
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/common/WebViewResizeObserver.java +59 -19
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/common/event/ComponentEvent.java +37 -0
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/common/event/ComponentEventSender.java +78 -0
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/common/event/KlarnaEventHandlerEventsUtil.java +53 -0
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/common/ui/ResizeObserverWrapperView.java +79 -0
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/common/ui/WrapperView.java +32 -0
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/common/{ArgumentsUtil.java → util/ArgumentsUtil.java} +1 -1
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/common/util/ParserUtil.java +36 -0
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/payments/KlarnaPaymentViewManager.java +1 -1
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/payments/PaymentViewWrapper.java +1 -1
- package/android/src/main/java/com/klarna/mobile/sdk/reactnative/standalonewebview/KlarnaStandaloneWebViewEventSender.java +1 -1
- package/android/src/newarch/java/com/klarna/mobile/sdk/reactnative/spec/RNKlarnaCheckoutViewSpec.java +31 -0
- package/android/src/oldarch/java/com/klarna/mobile/sdk/reactnative/spec/RNKlarnaCheckoutViewSpec.java +20 -0
- package/android/src/test/java/com/klarna/mobile/sdk/reactnative/KlarnaMobileSDKPackageTest.java +3 -1
- package/android/src/test/java/com/klarna/mobile/sdk/reactnative/common/event/ComponentEventSenderTest.java +85 -0
- package/android/src/test/java/com/klarna/mobile/sdk/reactnative/common/event/ComponentEventTest.java +73 -0
- package/android/src/test/java/com/klarna/mobile/sdk/reactnative/common/event/KlarnaEventHandlerEventsUtilTest.java +61 -0
- package/ios/RNKlarnaMobileSDK.xcodeproj/project.pbxproj +32 -0
- package/ios/Sources/KlarnaCheckoutViewManager.h +5 -0
- package/ios/Sources/KlarnaCheckoutViewManager.mm +65 -0
- package/ios/Sources/common/RNMobileSDKUtils.h +6 -0
- package/ios/Sources/common/RNMobileSDKUtils.mm +22 -0
- package/ios/Sources/view/newarch/KlarnaCheckoutViewWrapper.h +26 -0
- package/ios/Sources/view/newarch/KlarnaCheckoutViewWrapper.mm +153 -0
- package/ios/Sources/view/oldarch/KlarnaCheckoutViewWrapper.h +37 -0
- package/ios/Sources/view/oldarch/KlarnaCheckoutViewWrapper.mm +116 -0
- package/lib/commonjs/KlarnaCheckoutView.js +84 -0
- package/lib/commonjs/KlarnaCheckoutView.js.map +1 -0
- package/lib/commonjs/index.js +11 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/specs/KlarnaCheckoutViewNativeComponent.js +16 -0
- package/lib/commonjs/specs/KlarnaCheckoutViewNativeComponent.js.map +1 -0
- package/lib/commonjs/types/common/KlarnaMobileSDKError.js +2 -0
- package/lib/commonjs/types/common/KlarnaMobileSDKError.js.map +1 -0
- package/lib/commonjs/types/common/KlarnaProductEvent.js +2 -0
- package/lib/commonjs/types/common/KlarnaProductEvent.js.map +1 -0
- package/lib/module/KlarnaCheckoutView.js +74 -0
- package/lib/module/KlarnaCheckoutView.js.map +1 -0
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/specs/KlarnaCheckoutViewNativeComponent.js +7 -0
- package/lib/module/specs/KlarnaCheckoutViewNativeComponent.js.map +1 -0
- package/lib/module/types/common/KlarnaMobileSDKError.js +2 -0
- package/lib/module/types/common/KlarnaMobileSDKError.js.map +1 -0
- package/lib/module/types/common/KlarnaProductEvent.js +2 -0
- package/lib/module/types/common/KlarnaProductEvent.js.map +1 -0
- package/lib/typescript/KlarnaCheckoutView.d.ts +24 -0
- package/lib/typescript/KlarnaCheckoutView.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +1 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/specs/KlarnaCheckoutViewNativeComponent.d.ts +33 -0
- package/lib/typescript/specs/KlarnaCheckoutViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/types/common/KlarnaMobileSDKError.d.ts +6 -0
- package/lib/typescript/types/common/KlarnaMobileSDKError.d.ts.map +1 -0
- package/lib/typescript/types/common/KlarnaProductEvent.d.ts +7 -0
- package/lib/typescript/types/common/KlarnaProductEvent.d.ts.map +1 -0
- package/package.json +2 -2
- package/src/KlarnaCheckoutView.tsx +130 -0
- package/src/index.tsx +1 -0
- package/src/specs/KlarnaCheckoutViewNativeComponent.ts +58 -0
- package/src/types/common/KlarnaMobileSDKError.ts +5 -0
- package/src/types/common/KlarnaProductEvent.ts +4 -0
package/README.md
CHANGED
|
@@ -8,8 +8,9 @@
|
|
|
8
8
|
|
|
9
9
|
This library wraps Klarna Mobile SDK and exposes its functionality as React Native components. It
|
|
10
10
|
currently has the following components:
|
|
11
|
-
- `KlarnaPaymentView` to integrate Klarna Payments
|
|
12
|
-
- `KlarnaStandaloneWebView` to integrate Klarna Standalone WebView
|
|
11
|
+
- `KlarnaPaymentView` to integrate Klarna Payments
|
|
12
|
+
- `KlarnaStandaloneWebView` to integrate Klarna Standalone WebView
|
|
13
|
+
- `KlarnaCheckoutView` to integrate Klarna Checkout
|
|
13
14
|
|
|
14
15
|
This repository also includes a test application that you can use to see how it works.
|
|
15
16
|
|
package/android/build.gradle
CHANGED
|
@@ -110,16 +110,16 @@ dependencies {
|
|
|
110
110
|
|
|
111
111
|
implementation 'com.klarna.mobile:sdk:2.6.17'
|
|
112
112
|
|
|
113
|
-
testImplementation "junit:junit:4.13"
|
|
114
|
-
testImplementation 'androidx.test:core:1.
|
|
115
|
-
testImplementation "org.robolectric:robolectric:4.
|
|
116
|
-
testImplementation "org.mockito:mockito-core:
|
|
117
|
-
testImplementation "org.mockito:mockito-inline:2.
|
|
118
|
-
testImplementation "org.powermock:powermock-core:2.0.
|
|
119
|
-
testImplementation "org.powermock:powermock-api-mockito2:2.0.
|
|
120
|
-
testImplementation "org.powermock:powermock-module-junit4:2.0.
|
|
121
|
-
testImplementation "org.powermock:powermock-module-junit4-rule:2.0.
|
|
122
|
-
testImplementation "org.powermock:powermock-classloading-xstream:2.0.
|
|
113
|
+
testImplementation "junit:junit:4.13.2"
|
|
114
|
+
testImplementation 'androidx.test:core:1.5.0'
|
|
115
|
+
testImplementation "org.robolectric:robolectric:4.11.1"
|
|
116
|
+
testImplementation "org.mockito:mockito-core:2.28.2"
|
|
117
|
+
testImplementation "org.mockito:mockito-inline:2.28.2"
|
|
118
|
+
testImplementation "org.powermock:powermock-core:2.0.9"
|
|
119
|
+
testImplementation "org.powermock:powermock-api-mockito2:2.0.9"
|
|
120
|
+
testImplementation "org.powermock:powermock-module-junit4:2.0.9"
|
|
121
|
+
testImplementation "org.powermock:powermock-module-junit4-rule:2.0.9"
|
|
122
|
+
testImplementation "org.powermock:powermock-classloading-xstream:2.0.9"
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
// removed from the docs but we can keep it
|
|
@@ -8,6 +8,7 @@ import com.facebook.react.ReactPackage;
|
|
|
8
8
|
import com.facebook.react.bridge.NativeModule;
|
|
9
9
|
import com.facebook.react.bridge.ReactApplicationContext;
|
|
10
10
|
import com.facebook.react.uimanager.ViewManager;
|
|
11
|
+
import com.klarna.mobile.sdk.reactnative.checkout.KlarnaCheckoutViewManager;
|
|
11
12
|
import com.klarna.mobile.sdk.reactnative.payments.KlarnaPaymentViewManager;
|
|
12
13
|
import com.klarna.mobile.sdk.reactnative.standalonewebview.KlarnaStandaloneWebViewManager;
|
|
13
14
|
|
|
@@ -27,7 +28,8 @@ public class KlarnaMobileSDKPackage implements ReactPackage {
|
|
|
27
28
|
public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {
|
|
28
29
|
return List.of(
|
|
29
30
|
new KlarnaPaymentViewManager(reactContext),
|
|
30
|
-
new KlarnaStandaloneWebViewManager(reactContext, (Application) reactContext.getApplicationContext())
|
|
31
|
+
new KlarnaStandaloneWebViewManager(reactContext, (Application) reactContext.getApplicationContext()),
|
|
32
|
+
new KlarnaCheckoutViewManager(reactContext)
|
|
31
33
|
);
|
|
32
34
|
}
|
|
33
35
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
package com.klarna.mobile.sdk.reactnative.checkout;
|
|
2
|
+
|
|
3
|
+
import androidx.annotation.NonNull;
|
|
4
|
+
|
|
5
|
+
import com.klarna.mobile.sdk.KlarnaMobileSDKError;
|
|
6
|
+
import com.klarna.mobile.sdk.api.KlarnaEventHandler;
|
|
7
|
+
import com.klarna.mobile.sdk.api.KlarnaProductEvent;
|
|
8
|
+
import com.klarna.mobile.sdk.api.checkout.KlarnaCheckoutView;
|
|
9
|
+
import com.klarna.mobile.sdk.api.component.KlarnaComponent;
|
|
10
|
+
|
|
11
|
+
public class KlarnaCheckoutViewEventHandler implements KlarnaEventHandler {
|
|
12
|
+
|
|
13
|
+
private final KlarnaCheckoutViewEventSender klarnaCheckoutViewEventSender;
|
|
14
|
+
|
|
15
|
+
public KlarnaCheckoutViewEventHandler(KlarnaCheckoutViewEventSender klarnaCheckoutViewEventSender) {
|
|
16
|
+
this.klarnaCheckoutViewEventSender = klarnaCheckoutViewEventSender;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
@Override
|
|
20
|
+
public void onEvent(@NonNull KlarnaComponent klarnaComponent, @NonNull KlarnaProductEvent klarnaProductEvent) {
|
|
21
|
+
if (klarnaComponent instanceof KlarnaCheckoutView) {
|
|
22
|
+
klarnaCheckoutViewEventSender.sendKlarnaProductEvent((KlarnaCheckoutView) klarnaComponent, klarnaProductEvent);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@Override
|
|
27
|
+
public void onError(@NonNull KlarnaComponent klarnaComponent, @NonNull KlarnaMobileSDKError klarnaMobileSDKError) {
|
|
28
|
+
if (klarnaComponent instanceof KlarnaCheckoutView) {
|
|
29
|
+
klarnaCheckoutViewEventSender.sendKlarnaMobileSDKError((KlarnaCheckoutView) klarnaComponent, klarnaMobileSDKError);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
package com.klarna.mobile.sdk.reactnative.checkout;
|
|
2
|
+
|
|
3
|
+
import androidx.annotation.NonNull;
|
|
4
|
+
import androidx.annotation.Nullable;
|
|
5
|
+
|
|
6
|
+
import com.facebook.react.bridge.WritableMap;
|
|
7
|
+
import com.facebook.react.uimanager.events.EventDispatcher;
|
|
8
|
+
import com.klarna.mobile.sdk.KlarnaMobileSDKError;
|
|
9
|
+
import com.klarna.mobile.sdk.api.KlarnaProductEvent;
|
|
10
|
+
import com.klarna.mobile.sdk.api.checkout.KlarnaCheckoutView;
|
|
11
|
+
import com.klarna.mobile.sdk.reactnative.common.event.ComponentEvent;
|
|
12
|
+
import com.klarna.mobile.sdk.reactnative.common.event.ComponentEventSender;
|
|
13
|
+
import com.klarna.mobile.sdk.reactnative.common.event.KlarnaEventHandlerEventsUtil;
|
|
14
|
+
import com.klarna.mobile.sdk.reactnative.common.ui.ResizeObserverWrapperView;
|
|
15
|
+
import com.klarna.mobile.sdk.reactnative.common.util.ArgumentsUtil;
|
|
16
|
+
|
|
17
|
+
import java.lang.ref.WeakReference;
|
|
18
|
+
import java.util.Arrays;
|
|
19
|
+
import java.util.Collection;
|
|
20
|
+
import java.util.HashMap;
|
|
21
|
+
import java.util.Map;
|
|
22
|
+
|
|
23
|
+
public class KlarnaCheckoutViewEventSender extends ComponentEventSender<ResizeObserverWrapperView<KlarnaCheckoutView>> {
|
|
24
|
+
|
|
25
|
+
private static final String EVENT_NAME_ON_RESIZED = "onResized";
|
|
26
|
+
|
|
27
|
+
KlarnaCheckoutViewEventSender(@NonNull final Map<WeakReference<ResizeObserverWrapperView<KlarnaCheckoutView>>, EventDispatcher> viewToDispatcher) {
|
|
28
|
+
super(viewToDispatcher);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@Override
|
|
32
|
+
public Collection<String> getCallbackEventNames() {
|
|
33
|
+
return Arrays.asList(
|
|
34
|
+
KlarnaEventHandlerEventsUtil.EVENT_NAME_ON_EVENT,
|
|
35
|
+
KlarnaEventHandlerEventsUtil.EVENT_NAME_ON_ERROR,
|
|
36
|
+
EVENT_NAME_ON_RESIZED
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
public void sendKlarnaProductEvent(@Nullable KlarnaCheckoutView view, @NonNull KlarnaProductEvent klarnaProductEvent) {
|
|
41
|
+
KlarnaEventHandlerEventsUtil.sendKlarnaProductEvent(this, view, klarnaProductEvent);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
public void sendKlarnaMobileSDKError(@Nullable KlarnaCheckoutView view, @NonNull KlarnaMobileSDKError klarnaMobileSDKError) {
|
|
45
|
+
KlarnaEventHandlerEventsUtil.sendKlarnaMobileSDKError(this, view, klarnaMobileSDKError);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public void sendOnResizedEvent(@Nullable KlarnaCheckoutView view, int height) {
|
|
49
|
+
WritableMap params = ArgumentsUtil.createMap(
|
|
50
|
+
new HashMap<String, Object>() {{
|
|
51
|
+
put("height", String.valueOf(height));
|
|
52
|
+
}}
|
|
53
|
+
);
|
|
54
|
+
postEventForView(view, EVENT_NAME_ON_RESIZED, params);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
package com.klarna.mobile.sdk.reactnative.checkout;
|
|
2
|
+
|
|
3
|
+
import android.os.Handler;
|
|
4
|
+
|
|
5
|
+
import androidx.annotation.NonNull;
|
|
6
|
+
import androidx.annotation.Nullable;
|
|
7
|
+
|
|
8
|
+
import com.facebook.react.bridge.ReactApplicationContext;
|
|
9
|
+
import com.facebook.react.bridge.ReactContext;
|
|
10
|
+
import com.facebook.react.bridge.ReadableArray;
|
|
11
|
+
import com.facebook.react.uimanager.ThemedReactContext;
|
|
12
|
+
import com.facebook.react.uimanager.UIManagerHelper;
|
|
13
|
+
import com.facebook.react.uimanager.annotations.ReactProp;
|
|
14
|
+
import com.facebook.react.uimanager.events.EventDispatcher;
|
|
15
|
+
import com.klarna.mobile.sdk.api.KlarnaLoggingLevel;
|
|
16
|
+
import com.klarna.mobile.sdk.api.checkout.KlarnaCheckoutView;
|
|
17
|
+
import com.klarna.mobile.sdk.reactnative.common.WebViewResizeObserver;
|
|
18
|
+
import com.klarna.mobile.sdk.reactnative.common.ui.ResizeObserverWrapperView;
|
|
19
|
+
import com.klarna.mobile.sdk.reactnative.spec.RNKlarnaCheckoutViewSpec;
|
|
20
|
+
|
|
21
|
+
import java.lang.ref.WeakReference;
|
|
22
|
+
import java.util.HashMap;
|
|
23
|
+
import java.util.Map;
|
|
24
|
+
import java.util.Objects;
|
|
25
|
+
|
|
26
|
+
public class KlarnaCheckoutViewManager extends RNKlarnaCheckoutViewSpec<ResizeObserverWrapperView<KlarnaCheckoutView>> {
|
|
27
|
+
|
|
28
|
+
public static final String KLARNA_CHECKOUT_VIEW_REACT_CLASS = "RNKlarnaCheckoutView";
|
|
29
|
+
|
|
30
|
+
// Commands that can be triggered from RN
|
|
31
|
+
public static final String COMMAND_SET_SNIPPET = "setSnippet";
|
|
32
|
+
public static final String COMMAND_SUSPEND = "suspend";
|
|
33
|
+
public static final String COMMAND_RESUME = "resume";
|
|
34
|
+
|
|
35
|
+
private final ReactApplicationContext reactAppContext;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Store a map of views to event dispatchers so we send up events via the right views.
|
|
39
|
+
*/
|
|
40
|
+
private final Map<WeakReference<ResizeObserverWrapperView<KlarnaCheckoutView>>, EventDispatcher> viewToDispatcher;
|
|
41
|
+
|
|
42
|
+
private final KlarnaCheckoutViewEventSender eventSender;
|
|
43
|
+
private final KlarnaCheckoutViewEventHandler eventHandler;
|
|
44
|
+
|
|
45
|
+
public KlarnaCheckoutViewManager(ReactApplicationContext reactApplicationContext) {
|
|
46
|
+
super();
|
|
47
|
+
this.viewToDispatcher = new HashMap<>();
|
|
48
|
+
this.reactAppContext = reactApplicationContext;
|
|
49
|
+
this.eventSender = new KlarnaCheckoutViewEventSender(viewToDispatcher);
|
|
50
|
+
this.eventHandler = new KlarnaCheckoutViewEventHandler(eventSender);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
@NonNull
|
|
54
|
+
@Override
|
|
55
|
+
public String getName() {
|
|
56
|
+
return KLARNA_CHECKOUT_VIEW_REACT_CLASS;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@NonNull
|
|
60
|
+
@Override
|
|
61
|
+
protected ResizeObserverWrapperView<KlarnaCheckoutView> createViewInstance(@NonNull ThemedReactContext themedReactContext) {
|
|
62
|
+
KlarnaCheckoutView klarnaCheckoutView = new KlarnaCheckoutView(reactAppContext.getCurrentActivity(), null, 0, eventHandler);
|
|
63
|
+
klarnaCheckoutView.setLoggingLevel(KlarnaLoggingLevel.Verbose);
|
|
64
|
+
ResizeObserverWrapperView<KlarnaCheckoutView> view = new ResizeObserverWrapperView<>(reactAppContext, null, klarnaCheckoutView);
|
|
65
|
+
|
|
66
|
+
// Each view has its own event dispatcher.
|
|
67
|
+
EventDispatcher eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag((ReactContext) view.getContext(), view.getId());
|
|
68
|
+
viewToDispatcher.put(new WeakReference<>(view), eventDispatcher);
|
|
69
|
+
|
|
70
|
+
view.initiateWebViewResizeObserver(WebViewResizeObserver.TargetElement.CHECKOUT_CONTAINER, (resizeObserverWrapperView, newHeight) -> {
|
|
71
|
+
if (resizeObserverWrapperView == null) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (eventDispatcher == null) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
eventSender.sendOnResizedEvent(resizeObserverWrapperView.getView(), newHeight);
|
|
78
|
+
});
|
|
79
|
+
view.addInterfaceToWebView();
|
|
80
|
+
|
|
81
|
+
return view;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Exposes direct event types that will be accessible as prop "callbacks" from RN.
|
|
86
|
+
* <p>
|
|
87
|
+
* Structure must follow:
|
|
88
|
+
* { "<eventName>": {"registrationName": "<eventName>"} }
|
|
89
|
+
*/
|
|
90
|
+
@Nullable
|
|
91
|
+
@Override
|
|
92
|
+
public Map<String, Object> getExportedCustomDirectEventTypeConstants() {
|
|
93
|
+
return eventSender.getExportedCustomDirectEventTypeConstants();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Handles commands received from RN to a specific view.
|
|
98
|
+
*
|
|
99
|
+
* @param root view receiving the command
|
|
100
|
+
* @param commandId identifier of the command
|
|
101
|
+
* @param args array of command arguments
|
|
102
|
+
*/
|
|
103
|
+
@Override
|
|
104
|
+
public void receiveCommand(@NonNull ResizeObserverWrapperView<KlarnaCheckoutView> root, String commandId, @Nullable ReadableArray args) {
|
|
105
|
+
switch (commandId) {
|
|
106
|
+
case COMMAND_SET_SNIPPET:
|
|
107
|
+
setSnippet(root, args != null ? args.getString(0) : null);
|
|
108
|
+
break;
|
|
109
|
+
case COMMAND_SUSPEND:
|
|
110
|
+
suspend(root);
|
|
111
|
+
break;
|
|
112
|
+
case COMMAND_RESUME:
|
|
113
|
+
resume(root);
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
@ReactProp(name = "returnUrl")
|
|
119
|
+
@Override
|
|
120
|
+
public void setReturnUrl(ResizeObserverWrapperView<KlarnaCheckoutView> view, @Nullable String value) {
|
|
121
|
+
KlarnaCheckoutView checkoutView = view.getView();
|
|
122
|
+
if (checkoutView != null) {
|
|
123
|
+
if (!Objects.equals(value, checkoutView.getReturnURL())) {
|
|
124
|
+
checkoutView.setReturnURL(value);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
@Override
|
|
130
|
+
public void setSnippet(ResizeObserverWrapperView<KlarnaCheckoutView> view, String snippet) {
|
|
131
|
+
view.getView().setSnippet(snippet);
|
|
132
|
+
view.addInterfaceToWebView();
|
|
133
|
+
// Delay the injection of the resize observer to ensure the web view is ready
|
|
134
|
+
final Handler handler = new Handler();
|
|
135
|
+
handler.postDelayed(view::injectListenerToWebView, 500);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
@Override
|
|
139
|
+
public void suspend(ResizeObserverWrapperView<KlarnaCheckoutView> view) {
|
|
140
|
+
view.getView().suspend();
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
@Override
|
|
144
|
+
public void resume(ResizeObserverWrapperView<KlarnaCheckoutView> view) {
|
|
145
|
+
view.getView().resume();
|
|
146
|
+
}
|
|
147
|
+
}
|
package/android/src/main/java/com/klarna/mobile/sdk/reactnative/common/WebViewResizeObserver.java
CHANGED
|
@@ -15,11 +15,18 @@ public class WebViewResizeObserver {
|
|
|
15
15
|
void onResized(int value);
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
public enum TargetElement {
|
|
19
|
+
PAYMENT_CONTAINER,
|
|
20
|
+
CHECKOUT_CONTAINER
|
|
21
|
+
}
|
|
22
|
+
|
|
18
23
|
private static final String JS_INTERFACE_NAME = "NativeResizeObserver";
|
|
19
24
|
private final WeakReference<WebViewResizeObserverCallback> callback;
|
|
25
|
+
private final TargetElement targetElement;
|
|
20
26
|
|
|
21
|
-
public WebViewResizeObserver(WebViewResizeObserverCallback callback) {
|
|
27
|
+
public WebViewResizeObserver(WebViewResizeObserverCallback callback, TargetElement targetElement) {
|
|
22
28
|
this.callback = new WeakReference<>(callback);
|
|
29
|
+
this.targetElement = targetElement;
|
|
23
30
|
}
|
|
24
31
|
|
|
25
32
|
public void addInterface(WebView webView) {
|
|
@@ -78,23 +85,56 @@ public class WebViewResizeObserver {
|
|
|
78
85
|
}
|
|
79
86
|
|
|
80
87
|
private String initScript() {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
"
|
|
85
|
-
"
|
|
86
|
-
"
|
|
87
|
-
"
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
88
|
+
StringBuilder scriptBuilder = new StringBuilder();
|
|
89
|
+
switch (targetElement) {
|
|
90
|
+
case PAYMENT_CONTAINER:
|
|
91
|
+
scriptBuilder.append("console.log('Resize observer injection started');\n");
|
|
92
|
+
scriptBuilder.append("const container = document.querySelector('#payment-container');\n");
|
|
93
|
+
scriptBuilder.append("console.log('Resize observer container selected: ', container);\n");
|
|
94
|
+
scriptBuilder.append("const resizeObserver = new ResizeObserver((entries) => {\n" +
|
|
95
|
+
" console.log('Container size changed.', entries);\n" +
|
|
96
|
+
" for (let entry of entries) {\n" +
|
|
97
|
+
" console.log('New dimensions found: ', entry);\n" +
|
|
98
|
+
" if (entry.contentRect) {\n" +
|
|
99
|
+
" const height = entry.contentRect.height;\n" +
|
|
100
|
+
" const listener = window.NativeResizeObserver;\n" +
|
|
101
|
+
" if (listener != null) {\n" +
|
|
102
|
+
" listener.onResized(height);\n" +
|
|
103
|
+
" console.log('Container size sent to native: ', height);\n" +
|
|
104
|
+
" }\n" +
|
|
105
|
+
" }\n" +
|
|
106
|
+
" }\n" +
|
|
107
|
+
"});\n");
|
|
108
|
+
scriptBuilder.append("console.log('Resize observer initialized.');\n");
|
|
109
|
+
scriptBuilder.append("if (container != null) {\n" +
|
|
110
|
+
" resizeObserver.observe(container);\n" +
|
|
111
|
+
" console.log('Resize observer set to component.');\n" +
|
|
112
|
+
"}\n");
|
|
113
|
+
scriptBuilder.append("console.log('Resize observer injection finished.');");
|
|
114
|
+
break;
|
|
115
|
+
case CHECKOUT_CONTAINER:
|
|
116
|
+
scriptBuilder.append("const kcoIframe = document.getElementById('klarna-checkout-iframe')\n");
|
|
117
|
+
scriptBuilder.append("window.addEventListener('message', (message) => {\n" +
|
|
118
|
+
" if (message.source !== kcoIframe && message.data) {\n" +
|
|
119
|
+
" try {\n" +
|
|
120
|
+
" const data = JSON.parse(message.data)\n" +
|
|
121
|
+
" if (data.event === 'frame:checkout:resize') {\n" +
|
|
122
|
+
" const listener = window.NativeResizeObserver;\n" +
|
|
123
|
+
" if (listener != null) {\n" +
|
|
124
|
+
" const height = data.args[0];" +
|
|
125
|
+
" listener.onResized(height);\n" +
|
|
126
|
+
" console.log('Container size sent to native: ', height);\n" +
|
|
127
|
+
" } else {\n" +
|
|
128
|
+
" console.log('listener is null!')\n" +
|
|
129
|
+
" }\n" +
|
|
130
|
+
" }\n" +
|
|
131
|
+
" } catch (error) {\n" +
|
|
132
|
+
" console.log('Could not parse message.data', message);\n" +
|
|
133
|
+
" }\n" +
|
|
134
|
+
" }\n" +
|
|
135
|
+
" });\n");
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
return scriptBuilder.toString();
|
|
99
139
|
}
|
|
100
140
|
}
|
package/android/src/main/java/com/klarna/mobile/sdk/reactnative/common/event/ComponentEvent.java
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
package com.klarna.mobile.sdk.reactnative.common.event;
|
|
2
|
+
|
|
3
|
+
import androidx.annotation.IdRes;
|
|
4
|
+
import androidx.annotation.NonNull;
|
|
5
|
+
import androidx.annotation.Nullable;
|
|
6
|
+
|
|
7
|
+
import com.facebook.react.bridge.Arguments;
|
|
8
|
+
import com.facebook.react.bridge.WritableMap;
|
|
9
|
+
import com.facebook.react.uimanager.events.Event;
|
|
10
|
+
|
|
11
|
+
public class ComponentEvent extends Event<ComponentEvent> {
|
|
12
|
+
@NonNull
|
|
13
|
+
private final String eventName;
|
|
14
|
+
|
|
15
|
+
@Nullable
|
|
16
|
+
private final WritableMap additionalParams;
|
|
17
|
+
|
|
18
|
+
public ComponentEvent(@IdRes int viewId, @NonNull String eventName, @Nullable WritableMap additionalParams) {
|
|
19
|
+
super(viewId);
|
|
20
|
+
this.eventName = eventName;
|
|
21
|
+
this.additionalParams = additionalParams;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@Override
|
|
25
|
+
public String getEventName() {
|
|
26
|
+
return eventName;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@Nullable
|
|
30
|
+
@Override
|
|
31
|
+
protected WritableMap getEventData() {
|
|
32
|
+
if (additionalParams != null) {
|
|
33
|
+
return additionalParams;
|
|
34
|
+
}
|
|
35
|
+
return Arguments.createMap();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
package com.klarna.mobile.sdk.reactnative.common.event;
|
|
2
|
+
|
|
3
|
+
import android.view.View;
|
|
4
|
+
|
|
5
|
+
import androidx.annotation.NonNull;
|
|
6
|
+
import androidx.annotation.Nullable;
|
|
7
|
+
|
|
8
|
+
import com.facebook.react.bridge.ReactContext;
|
|
9
|
+
import com.facebook.react.bridge.WritableMap;
|
|
10
|
+
import com.facebook.react.common.MapBuilder;
|
|
11
|
+
import com.facebook.react.uimanager.UIManagerHelper;
|
|
12
|
+
import com.facebook.react.uimanager.events.EventDispatcher;
|
|
13
|
+
import com.klarna.mobile.sdk.reactnative.common.ui.WrapperView;
|
|
14
|
+
|
|
15
|
+
import java.lang.ref.WeakReference;
|
|
16
|
+
import java.util.Collection;
|
|
17
|
+
import java.util.Map;
|
|
18
|
+
|
|
19
|
+
public abstract class ComponentEventSender<T extends View> {
|
|
20
|
+
private final Map<WeakReference<T>, EventDispatcher> viewToDispatcher;
|
|
21
|
+
|
|
22
|
+
protected ComponentEventSender(@NonNull final Map<WeakReference<T>, EventDispatcher> viewToDispatcher) {
|
|
23
|
+
this.viewToDispatcher = viewToDispatcher;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
protected void postEvent(@Nullable EventDispatcher eventDispatcher, @NonNull ComponentEvent event) {
|
|
27
|
+
if (eventDispatcher != null) {
|
|
28
|
+
eventDispatcher.dispatchEvent(event);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
protected ComponentEvent createEvent(@Nullable View view, @NonNull String eventName, @Nullable WritableMap params) {
|
|
33
|
+
T viewReference = getView(view);
|
|
34
|
+
if (viewReference == null) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
return new ComponentEvent(viewReference.getId(), eventName, params);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
protected void postEventForView(@Nullable View view, @NonNull String eventName, @Nullable WritableMap params) {
|
|
41
|
+
T viewReference = getView(view);
|
|
42
|
+
if (viewReference != null) {
|
|
43
|
+
EventDispatcher eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag((ReactContext) viewReference.getContext(), viewReference.getId());
|
|
44
|
+
postEvent(eventDispatcher, createEvent(viewReference, eventName, params));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@Nullable
|
|
49
|
+
private T getView(@Nullable View view) {
|
|
50
|
+
if (view == null) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
for (WeakReference<T> reference : viewToDispatcher.keySet()) {
|
|
54
|
+
T viewReference = reference.get();
|
|
55
|
+
if (viewReference != null && viewReference == view) {
|
|
56
|
+
return viewReference;
|
|
57
|
+
}
|
|
58
|
+
if (viewReference instanceof WrapperView) {
|
|
59
|
+
View wrappedView = ((WrapperView) viewReference).getView();
|
|
60
|
+
if (wrappedView == view) {
|
|
61
|
+
return viewReference;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public Map<String, Object> getExportedCustomDirectEventTypeConstants() {
|
|
69
|
+
MapBuilder.Builder<String, Object> builder = MapBuilder.builder();
|
|
70
|
+
Collection<String> eventNames = getCallbackEventNames();
|
|
71
|
+
for (String eventName : eventNames) {
|
|
72
|
+
builder.put(eventName, MapBuilder.of("registrationName", eventName));
|
|
73
|
+
}
|
|
74
|
+
return builder.build();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
public abstract Collection<String> getCallbackEventNames();
|
|
78
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
package com.klarna.mobile.sdk.reactnative.common.event;
|
|
2
|
+
|
|
3
|
+
import android.view.View;
|
|
4
|
+
|
|
5
|
+
import androidx.annotation.NonNull;
|
|
6
|
+
import androidx.annotation.Nullable;
|
|
7
|
+
|
|
8
|
+
import com.facebook.react.bridge.ReadableMap;
|
|
9
|
+
import com.facebook.react.bridge.WritableMap;
|
|
10
|
+
import com.klarna.mobile.sdk.KlarnaMobileSDKError;
|
|
11
|
+
import com.klarna.mobile.sdk.api.KlarnaProductEvent;
|
|
12
|
+
import com.klarna.mobile.sdk.reactnative.common.util.ArgumentsUtil;
|
|
13
|
+
import com.klarna.mobile.sdk.reactnative.common.util.ParserUtil;
|
|
14
|
+
|
|
15
|
+
import java.util.HashMap;
|
|
16
|
+
|
|
17
|
+
public class KlarnaEventHandlerEventsUtil {
|
|
18
|
+
|
|
19
|
+
public static final String EVENT_NAME_ON_EVENT = "onEvent";
|
|
20
|
+
public static final String EVENT_NAME_ON_ERROR = "onError";
|
|
21
|
+
|
|
22
|
+
private static final String PARAM_NAME_ACTION = "action";
|
|
23
|
+
private static final String PARAM_NAME_PARAMS = "params";
|
|
24
|
+
private static final String PARAM_NAME_IS_FATAL = "isFatal";
|
|
25
|
+
private static final String PARAM_NAME_MESSAGE = "message";
|
|
26
|
+
private static final String PARAM_NAME_NAME = "name";
|
|
27
|
+
private static final String PARAM_NAME_PRODUCT_EVENT = "productEvent";
|
|
28
|
+
|
|
29
|
+
public static <T extends View> void sendKlarnaProductEvent(@NonNull ComponentEventSender<T> componentEventSender, @Nullable View view, @NonNull KlarnaProductEvent klarnaProductEvent) {
|
|
30
|
+
String stringifiedParams = ParserUtil.toJson(klarnaProductEvent.getParams());
|
|
31
|
+
String paramsJson = stringifiedParams == null ? "{}" : stringifiedParams;
|
|
32
|
+
ReadableMap eventMap = ArgumentsUtil.createMap(new HashMap<String, Object>() {{
|
|
33
|
+
put(PARAM_NAME_ACTION, klarnaProductEvent.getAction());
|
|
34
|
+
put(PARAM_NAME_PARAMS, paramsJson);
|
|
35
|
+
}});
|
|
36
|
+
WritableMap params = ArgumentsUtil.createMap(new HashMap<String, Object>() {{
|
|
37
|
+
put(PARAM_NAME_PRODUCT_EVENT, eventMap);
|
|
38
|
+
}});
|
|
39
|
+
componentEventSender.postEventForView(view, EVENT_NAME_ON_EVENT, params);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public static <T extends View> void sendKlarnaMobileSDKError(@NonNull ComponentEventSender<T> componentEventSender, @Nullable View view, @NonNull KlarnaMobileSDKError klarnaMobileSDKError) {
|
|
43
|
+
ReadableMap eventMap = ArgumentsUtil.createMap(new HashMap<String, Object>() {{
|
|
44
|
+
put(PARAM_NAME_NAME, klarnaMobileSDKError.getName());
|
|
45
|
+
put(PARAM_NAME_MESSAGE, klarnaMobileSDKError.getMessage());
|
|
46
|
+
put(PARAM_NAME_IS_FATAL, klarnaMobileSDKError.isFatal());
|
|
47
|
+
}});
|
|
48
|
+
WritableMap params = ArgumentsUtil.createMap(new HashMap<String, Object>() {{
|
|
49
|
+
put(PARAM_NAME_PRODUCT_EVENT, eventMap);
|
|
50
|
+
}});
|
|
51
|
+
componentEventSender.postEventForView(view, EVENT_NAME_ON_EVENT, params);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
package com.klarna.mobile.sdk.reactnative.common.ui;
|
|
2
|
+
|
|
3
|
+
import android.content.Context;
|
|
4
|
+
import android.util.AttributeSet;
|
|
5
|
+
import android.view.View;
|
|
6
|
+
import android.view.ViewGroup;
|
|
7
|
+
import android.webkit.WebView;
|
|
8
|
+
|
|
9
|
+
import androidx.annotation.NonNull;
|
|
10
|
+
import androidx.annotation.Nullable;
|
|
11
|
+
|
|
12
|
+
import com.facebook.react.bridge.ReactApplicationContext;
|
|
13
|
+
import com.klarna.mobile.sdk.reactnative.common.WebViewResizeObserver;
|
|
14
|
+
|
|
15
|
+
import java.lang.ref.WeakReference;
|
|
16
|
+
|
|
17
|
+
public class ResizeObserverWrapperView<T extends ViewGroup> extends WrapperView<T> {
|
|
18
|
+
|
|
19
|
+
public interface OnResizedListener<T extends ViewGroup> {
|
|
20
|
+
void onResized(ResizeObserverWrapperView<T> resizeObserverWrapperView, int newHeight);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
private WebViewResizeObserver webViewResizeObserver;
|
|
24
|
+
private WebViewResizeObserver.WebViewResizeObserverCallback webViewResizeObserverCallback;
|
|
25
|
+
private OnResizedListener<T> onResizedListener;
|
|
26
|
+
|
|
27
|
+
public ResizeObserverWrapperView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
|
28
|
+
super(context, attrs, defStyleAttr);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public ResizeObserverWrapperView(ReactApplicationContext context, AttributeSet attrs, T view) {
|
|
32
|
+
super(context, attrs, view);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public void initiateWebViewResizeObserver(WebViewResizeObserver.TargetElement targetElement, OnResizedListener<T> onResizedListener) {
|
|
36
|
+
this.onResizedListener = onResizedListener;
|
|
37
|
+
this.webViewResizeObserverCallback = new WebViewResizeObserver.WebViewResizeObserverCallback() {
|
|
38
|
+
|
|
39
|
+
private final WeakReference<OnResizedListener<T>> onResizedListenerWeakReference = new WeakReference<>(ResizeObserverWrapperView.this.onResizedListener);
|
|
40
|
+
|
|
41
|
+
@Override
|
|
42
|
+
public void onResized(int value) {
|
|
43
|
+
OnResizedListener<T> listener = onResizedListenerWeakReference.get();
|
|
44
|
+
if (listener != null) {
|
|
45
|
+
listener.onResized(ResizeObserverWrapperView.this, value);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
this.webViewResizeObserver = new WebViewResizeObserver(webViewResizeObserverCallback, targetElement);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
public void addInterfaceToWebView() {
|
|
53
|
+
WebView webView = findWebView(getView());
|
|
54
|
+
if (webView != null && webViewResizeObserver != null) {
|
|
55
|
+
webViewResizeObserver.addInterface(webView);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
public void injectListenerToWebView() {
|
|
60
|
+
WebView webView = findWebView(getView());
|
|
61
|
+
if (webView != null && webViewResizeObserver != null) {
|
|
62
|
+
webViewResizeObserver.injectListener(webView);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
private WebView findWebView(T view) {
|
|
67
|
+
if (view == null) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
for (int i = 0; i < view.getChildCount(); i++) {
|
|
71
|
+
View child = view.getChildAt(i);
|
|
72
|
+
|
|
73
|
+
if (child instanceof WebView) {
|
|
74
|
+
return (WebView) child;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
}
|