react-native-klarna-inapp-sdk 2.4.3 → 2.4.5

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 (22) hide show
  1. package/android/build.gradle +10 -3
  2. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/common/event/KlarnaEventHandlerEventsUtil.java +5 -7
  3. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/common/serializer/DynamicMapSerializer.kt +138 -0
  4. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/common/util/ArgumentsUtil.java +2 -3
  5. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/common/util/ParserUtil.kt +27 -0
  6. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/signin/KlarnaSignInEventsMapper.java +37 -8
  7. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/signin/model/KlarnaSignInTokenSerializable.kt +32 -0
  8. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/standalonewebview/KlarnaStandaloneWebViewEventSender.java +3 -3
  9. package/android/src/test/java/com/klarna/mobile/sdk/reactnative/common/serializer/DynamicMapSerializerTest.kt +229 -0
  10. package/android/src/test/java/com/klarna/mobile/sdk/reactnative/common/util/ParserUtilTest.kt +39 -0
  11. package/ios/Sources/signIn/KlarnaSignInData.h +1 -0
  12. package/ios/Sources/signIn/KlarnaSignInData.mm +2 -0
  13. package/ios/Sources/signIn/KlarnaSignInModuleImpl.mm +1 -0
  14. package/ios/Sources/view/newarch/KlarnaCheckoutViewWrapper.mm +1 -0
  15. package/ios/Sources/view/newarch/KlarnaStandaloneWebViewWrapper.mm +1 -0
  16. package/ios/Sources/view/newarch/PaymentViewWrapper.mm +1 -0
  17. package/ios/Sources/view/oldarch/KlarnaCheckoutViewWrapper.mm +1 -0
  18. package/ios/Sources/view/oldarch/KlarnaStandaloneWebViewWrapper.mm +1 -0
  19. package/ios/Sources/view/oldarch/PaymentViewWrapper.mm +1 -0
  20. package/package.json +1 -1
  21. package/react-native-klarna-inapp-sdk.podspec +1 -1
  22. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/common/util/ParserUtil.java +0 -36
@@ -31,8 +31,6 @@ def isNewArchitectureEnabled() {
31
31
  return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true"
32
32
  }
33
33
 
34
- def appProject = rootProject.allprojects.find { it.plugins.hasPlugin('com.android.application') }
35
-
36
34
  def supportsNamespace() {
37
35
  def parsed = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION.tokenize('.')
38
36
  def major = parsed[0].toInteger()
@@ -46,6 +44,9 @@ def supportsNamespace() {
46
44
  return major >= 8
47
45
  }
48
46
 
47
+ plugins {
48
+ id "org.jetbrains.kotlin.plugin.serialization" version "2.2.0"
49
+ }
49
50
  apply plugin: 'com.android.library'
50
51
  apply plugin: 'kotlin-android'
51
52
  if (isNewArchitectureEnabled()) {
@@ -109,13 +110,19 @@ dependencies {
109
110
  //noinspection GradleDynamicVersion
110
111
  implementation "com.facebook.react:react-native:${getExtOrFallback('reactnativeVersion', '+')}"
111
112
 
112
- implementation 'com.klarna.mobile:sdk:2.6.29'
113
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:${getExtOrDefault('kotlinVersion')}"
114
+ implementation "org.jetbrains.kotlin:kotlin-reflect:${getExtOrDefault('kotlinVersion')}"
115
+ implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0'
116
+
117
+ implementation 'com.klarna.mobile:sdk:2.7.1'
113
118
 
114
119
  testImplementation "junit:junit:4.13.2"
115
120
  testImplementation 'androidx.test:core:1.5.0'
116
121
  testImplementation "org.robolectric:robolectric:4.11.1"
117
122
  testImplementation "org.mockito:mockito-core:3.12.4"
118
123
  testImplementation "org.mockito:mockito-inline:3.12.4"
124
+ testImplementation "org.jetbrains.kotlin:kotlin-test-junit:${getExtOrDefault('kotlinVersion')}"
125
+ testImplementation "io.mockk:mockk:1.14.5"
119
126
  }
120
127
 
121
128
  // removed from the docs but we can keep it
@@ -5,19 +5,16 @@ import android.view.View;
5
5
  import androidx.annotation.NonNull;
6
6
  import androidx.annotation.Nullable;
7
7
 
8
- import com.facebook.react.bridge.Promise;
9
8
  import com.facebook.react.bridge.ReadableMap;
10
9
  import com.facebook.react.bridge.WritableMap;
11
- import com.google.gson.reflect.TypeToken;
12
10
  import com.klarna.mobile.sdk.KlarnaMobileSDKError;
13
11
  import com.klarna.mobile.sdk.api.KlarnaProductEvent;
14
- import com.klarna.mobile.sdk.api.signin.model.KlarnaSignInToken;
12
+ import com.klarna.mobile.sdk.reactnative.common.serializer.DynamicMapSerializer;
15
13
  import com.klarna.mobile.sdk.reactnative.common.util.ArgumentsUtil;
16
14
  import com.klarna.mobile.sdk.reactnative.common.util.ParserUtil;
17
15
  import com.klarna.mobile.sdk.reactnative.signin.KlarnaSignInData;
18
16
  import com.klarna.mobile.sdk.reactnative.signin.KlarnaSignInEventsMapper;
19
17
 
20
- import java.lang.reflect.Type;
21
18
  import java.util.HashMap;
22
19
  import java.util.Map;
23
20
 
@@ -35,7 +32,7 @@ public class KlarnaEventHandlerEventsUtil {
35
32
  private static final String PARAM_NAME_PRODUCT_EVENT = "productEvent";
36
33
 
37
34
  public static <T extends View> void sendKlarnaProductEvent(@NonNull ComponentEventSender<T> componentEventSender, @Nullable View view, @NonNull KlarnaProductEvent klarnaProductEvent) {
38
- String stringifiedParams = ParserUtil.toJson(klarnaProductEvent.getParams());
35
+ String stringifiedParams = ParserUtil.INSTANCE.toJson(DynamicMapSerializer.INSTANCE, klarnaProductEvent.getParams());
39
36
  String paramsJson = stringifiedParams == null ? "{}" : stringifiedParams;
40
37
  ReadableMap eventMap = ArgumentsUtil.createMap(new HashMap<String, Object>() {{
41
38
  put(PARAM_NAME_ACTION, klarnaProductEvent.getAction());
@@ -64,9 +61,10 @@ public class KlarnaEventHandlerEventsUtil {
64
61
  return;
65
62
  }
66
63
  Map<String, Object> updatedParams = new HashMap<>();
67
- for(Map.Entry<String, Object> entry : klarnaProductEvent.getParams().entrySet()) {
64
+ for (Map.Entry<String, Object> entry : klarnaProductEvent.getParams().entrySet()) {
68
65
  String updatedKey = KlarnaSignInEventsMapper.mapSignInParamName(entry.getKey());
69
- updatedParams.put(updatedKey, entry.getValue());
66
+ Object updatedValue = KlarnaSignInEventsMapper.transformSignInParamValue(entry.getKey(), entry.getValue());
67
+ updatedParams.put(updatedKey, updatedValue);
70
68
  }
71
69
  String eventName = KlarnaSignInEventsMapper.mapSignInEventName(klarnaProductEvent.getAction());
72
70
  ReadableMap eventMap = ArgumentsUtil.createMap(new HashMap<String, Object>() {{
@@ -0,0 +1,138 @@
1
+ package com.klarna.mobile.sdk.reactnative.common.serializer
2
+
3
+ import kotlinx.serialization.KSerializer
4
+ import kotlinx.serialization.descriptors.SerialDescriptor
5
+ import kotlinx.serialization.descriptors.buildClassSerialDescriptor
6
+ import kotlinx.serialization.encoding.Decoder
7
+ import kotlinx.serialization.encoding.Encoder
8
+ import kotlinx.serialization.json.JsonArray
9
+ import kotlinx.serialization.json.JsonDecoder
10
+ import kotlinx.serialization.json.JsonElement
11
+ import kotlinx.serialization.json.JsonEncoder
12
+ import kotlinx.serialization.json.JsonNull
13
+ import kotlinx.serialization.json.JsonObject
14
+ import kotlinx.serialization.json.JsonPrimitive
15
+ import kotlinx.serialization.json.buildJsonArray
16
+ import kotlinx.serialization.json.buildJsonObject
17
+ import kotlinx.serialization.json.doubleOrNull
18
+ import kotlinx.serialization.json.floatOrNull
19
+ import kotlinx.serialization.json.intOrNull
20
+ import kotlinx.serialization.json.jsonObject
21
+ import kotlinx.serialization.json.longOrNull
22
+ import kotlinx.serialization.modules.SerializersModule
23
+ import kotlinx.serialization.serializerOrNull
24
+ import kotlin.reflect.full.memberProperties
25
+
26
+ object DynamicMapSerializer : KSerializer<Map<String, Any?>> {
27
+ override val descriptor: SerialDescriptor =
28
+ buildClassSerialDescriptor("EnhancedDynamicMap")
29
+
30
+ override fun serialize(
31
+ encoder: Encoder,
32
+ value: Map<String, Any?>,
33
+ ) {
34
+ val jsonEncoder = encoder as? JsonEncoder ?: error("Only JSON is supported")
35
+ val jsonObject =
36
+ buildJsonObject {
37
+ value.forEach { (key, any) ->
38
+ put(key, serializeValue(any, jsonEncoder))
39
+ }
40
+ }
41
+ jsonEncoder.encodeJsonElement(jsonObject)
42
+ }
43
+
44
+ override fun deserialize(decoder: Decoder): Map<String, Any?> {
45
+ val jsonDecoder = decoder as? JsonDecoder ?: error("Only JSON is supported")
46
+ val jsonObject = jsonDecoder.decodeJsonElement().jsonObject
47
+ return jsonObject.mapValues { (_, element) -> deserializeValue(element) }
48
+ }
49
+
50
+ private fun serializeValue(value: Any?, encoder: JsonEncoder): JsonElement =
51
+ when (value) {
52
+ null -> JsonNull
53
+ is Boolean -> JsonPrimitive(value)
54
+ is Byte -> JsonPrimitive(value)
55
+ is Short -> JsonPrimitive(value)
56
+ is Int -> JsonPrimitive(value)
57
+ is Long -> JsonPrimitive(value)
58
+ is Float -> JsonPrimitive(value)
59
+ is Double -> JsonPrimitive(value)
60
+ is String -> JsonPrimitive(value)
61
+ is Char -> JsonPrimitive(value.toString())
62
+ is Enum<*> -> JsonPrimitive(value.toString())
63
+ is Map<*, *> -> {
64
+ buildJsonObject {
65
+ value.forEach { (k, v) ->
66
+ put(k.toString(), serializeValue(v, encoder))
67
+ }
68
+ }
69
+ }
70
+
71
+ is Collection<*> -> {
72
+ buildJsonArray {
73
+ value.forEach { add(serializeValue(it, encoder)) }
74
+ }
75
+ }
76
+
77
+ is Array<*> -> {
78
+ buildJsonArray {
79
+ value.forEach { add(serializeValue(it, encoder)) }
80
+ }
81
+ }
82
+
83
+ else -> {
84
+ serializerFor(encoder.serializersModule, value)?.let { serializer ->
85
+ // Use the serializer to convert the object to JsonElement
86
+ val jsonElement = encoder.json.encodeToJsonElement(serializer, value)
87
+ jsonElement
88
+ } ?: run {
89
+ // Check if it's a data class
90
+ if (value::class.isData) {
91
+ // Convert data class to Map by using reflection
92
+ val properties = value::class.memberProperties
93
+ .associate { it.name to it.call(value) }
94
+
95
+ buildJsonObject {
96
+ properties.forEach { (k, v) ->
97
+ put(k, serializeValue(v, encoder))
98
+ }
99
+ }
100
+ } else {
101
+ JsonPrimitive(value.toString()) // Fallback to string representation
102
+ }
103
+ }
104
+ }
105
+ }
106
+
107
+ private fun deserializeValue(element: JsonElement): Any? =
108
+ when (element) {
109
+ is JsonNull -> null
110
+ is JsonPrimitive -> {
111
+ when {
112
+ element.isString -> element.content
113
+ element.content.equals("true", ignoreCase = true) -> true
114
+ element.content.equals("false", ignoreCase = true) -> false
115
+ // Try parsing as numbers with proper type detection
116
+ element.content.contains('.') -> {
117
+ element.doubleOrNull ?: element.floatOrNull ?: element.content
118
+ }
119
+
120
+ else -> {
121
+ element.longOrNull ?: element.intOrNull ?: element.content
122
+ }
123
+ }
124
+ }
125
+
126
+ is JsonObject -> element.mapValues { (_, value) -> deserializeValue(value) }
127
+ is JsonArray -> element.map { deserializeValue(it) }
128
+ }
129
+
130
+ private fun serializerFor(
131
+ serializersModule: SerializersModule,
132
+ obj: Any?,
133
+ ): KSerializer<Any>? {
134
+ return obj?.let {
135
+ serializersModule.serializerOrNull(obj::class.java)
136
+ }
137
+ }
138
+ }
@@ -5,6 +5,7 @@ import com.facebook.react.bridge.ReadableArray;
5
5
  import com.facebook.react.bridge.ReadableMap;
6
6
  import com.facebook.react.bridge.WritableArray;
7
7
  import com.facebook.react.bridge.WritableMap;
8
+ import com.klarna.mobile.sdk.reactnative.common.serializer.DynamicMapSerializer;
8
9
 
9
10
  import org.json.JSONException;
10
11
  import org.json.JSONObject;
@@ -13,8 +14,6 @@ import java.util.Iterator;
13
14
  import java.util.List;
14
15
  import java.util.Map;
15
16
 
16
- import okhttp3.internal.Util;
17
-
18
17
  public class ArgumentsUtil {
19
18
 
20
19
  public static WritableMap createMap(Map<String, Object> sourceMap) {
@@ -67,7 +66,7 @@ public class ArgumentsUtil {
67
66
  }
68
67
 
69
68
  public static WritableMap createMapUsingJSONString(Map<String, Object> sourceMap) {
70
- String jsonString = ParserUtil.toJson(sourceMap);
69
+ String jsonString = ParserUtil.INSTANCE.toJson(DynamicMapSerializer.INSTANCE, sourceMap);
71
70
  WritableMap map = Arguments.createMap();
72
71
  try {
73
72
  JSONObject jsonObject = new JSONObject(jsonString);
@@ -0,0 +1,27 @@
1
+ package com.klarna.mobile.sdk.reactnative.common.util
2
+
3
+ import kotlinx.serialization.SerializationStrategy
4
+ import kotlinx.serialization.json.Json
5
+ import kotlinx.serialization.json.JsonElement
6
+
7
+ object ParserUtil {
8
+ val json: Json by lazy {
9
+ Json {
10
+ ignoreUnknownKeys = true
11
+ }
12
+ }
13
+
14
+ fun <T> toJson(
15
+ serializer: SerializationStrategy<T>,
16
+ src: T,
17
+ ): String {
18
+ val res = json.encodeToString(serializer, src)
19
+ return res
20
+ }
21
+
22
+ inline fun <reified T> toJson(
23
+ src: T,
24
+ ): String = json.encodeToString(src)
25
+
26
+ fun parse(json: String): JsonElement = this.json.parseToJsonElement(json)
27
+ }
@@ -1,5 +1,8 @@
1
1
  package com.klarna.mobile.sdk.reactnative.signin;
2
2
 
3
+ import com.klarna.mobile.sdk.api.signin.model.KlarnaSignInToken;
4
+ import com.klarna.mobile.sdk.reactnative.signin.model.KlarnaSignInTokenSerializable;
5
+
3
6
  import java.util.Collections;
4
7
  import java.util.HashMap;
5
8
  import java.util.Map;
@@ -22,19 +25,45 @@ public class KlarnaSignInEventsMapper {
22
25
  return errorsMap.get(key);
23
26
  }
24
27
 
28
+ private static final Map<String, String> EVENTS_MAP = new HashMap<>() {
29
+ {
30
+ put("KlarnaSignInToken", "KlarnaSignInToken");
31
+ put("KlarnaSignInUserCancelled", "KlarnaSignInUserCancelled");
32
+ }
33
+ };
34
+
25
35
  public static String mapSignInEventName(String key) {
26
- Map<String, String> eventsMap = new HashMap<>();
27
- eventsMap.put("KlarnaSignInToken", "KlarnaSignInToken");
28
- eventsMap.put("KlarnaSignInUserCancelled", "KlarnaSignInUserCancelled");
29
- if (eventsMap.get(key) == null) {
36
+ if (EVENTS_MAP.get(key) == null) {
30
37
  return key;
31
38
  }
32
- return eventsMap.get(key);
39
+ return EVENTS_MAP.get(key);
33
40
  }
34
41
 
42
+ private static final Map<String, String> PARAMS_MAP = Collections.singletonMap("KlarnaSignInToken", "KlarnaSignInToken");
43
+
35
44
  public static String mapSignInParamName(String key) {
36
- Map<String, String> paramsMap = new HashMap<>();
37
- paramsMap.put("KlarnaSignInToken", "KlarnaSignInToken");
38
- return paramsMap.get(key);
45
+ if (EVENTS_MAP.containsKey(key)) {
46
+ return PARAMS_MAP.get(key);
47
+ }
48
+ return key;
49
+ }
50
+
51
+ private static final Map<String, ValueTransformer<Object>> TRANSFORMER_MAP = Collections.singletonMap("KlarnaSignInToken", value -> {
52
+ if (value instanceof KlarnaSignInToken) {
53
+ return KlarnaSignInTokenSerializable.Companion.from((KlarnaSignInToken) value);
54
+ }
55
+ return value;
56
+ });
57
+
58
+ public static Object transformSignInParamValue(String key, Object value) {
59
+ ValueTransformer<Object> transformer = TRANSFORMER_MAP.get(key);
60
+ if (transformer != null) {
61
+ return transformer.transform(value);
62
+ }
63
+ return value;
64
+ }
65
+
66
+ public interface ValueTransformer<T> {
67
+ T transform(Object value);
39
68
  }
40
69
  }
@@ -0,0 +1,32 @@
1
+ package com.klarna.mobile.sdk.reactnative.signin.model
2
+
3
+ import com.klarna.mobile.sdk.api.signin.model.KlarnaSignInToken
4
+ import kotlinx.serialization.SerialName
5
+ import kotlinx.serialization.Serializable
6
+
7
+ @Serializable
8
+ data class KlarnaSignInTokenSerializable(
9
+ @SerialName("access_token")
10
+ val accessToken: String? = null,
11
+ @SerialName("refresh_token")
12
+ val refreshToken: String? = null,
13
+ @SerialName("id_token")
14
+ val idToken: String? = null,
15
+ @SerialName("expires_in")
16
+ val expiresIn: String? = null,
17
+ @SerialName("scope")
18
+ val scope: String? = null,
19
+ @SerialName("token_type")
20
+ val tokenType: String? = null,
21
+ ) {
22
+ companion object {
23
+ fun from(klarnaSignInToken: KlarnaSignInToken) = KlarnaSignInTokenSerializable(
24
+ accessToken = klarnaSignInToken.accessToken,
25
+ refreshToken = klarnaSignInToken.refreshToken,
26
+ idToken = klarnaSignInToken.idToken,
27
+ expiresIn = klarnaSignInToken.expiresIn,
28
+ scope = klarnaSignInToken.scope,
29
+ tokenType = klarnaSignInToken.tokenType
30
+ )
31
+ }
32
+ }
@@ -8,10 +8,11 @@ import com.facebook.react.bridge.ReadableMap;
8
8
  import com.facebook.react.bridge.WritableMap;
9
9
  import com.facebook.react.uimanager.UIManagerHelper;
10
10
  import com.facebook.react.uimanager.events.EventDispatcher;
11
- import com.google.gson.Gson;
12
11
  import com.klarna.mobile.sdk.api.KlarnaProductEvent;
13
12
  import com.klarna.mobile.sdk.api.standalonewebview.KlarnaStandaloneWebView;
13
+ import com.klarna.mobile.sdk.reactnative.common.serializer.DynamicMapSerializer;
14
14
  import com.klarna.mobile.sdk.reactnative.common.util.ArgumentsUtil;
15
+ import com.klarna.mobile.sdk.reactnative.common.util.ParserUtil;
15
16
 
16
17
  import java.lang.ref.WeakReference;
17
18
  import java.util.HashMap;
@@ -39,7 +40,6 @@ public class KlarnaStandaloneWebViewEventSender {
39
40
  private static final String PARAM_NAME_PARAMS = "params";
40
41
  private static final String PARAM_NAME_DID_CRASH = "didCrash";
41
42
 
42
- private final Gson gson = new Gson();
43
43
  private final WeakReference<ReactContext> reactContextWeakReference;
44
44
  private final Map<WeakReference<KlarnaStandaloneWebView>, EventDispatcher> viewToDispatcher;
45
45
 
@@ -78,7 +78,7 @@ public class KlarnaStandaloneWebViewEventSender {
78
78
  public void sendKlarnaMessageEvent(@Nullable KlarnaStandaloneWebView view, @NonNull KlarnaProductEvent klarnaProductEvent) {
79
79
  String paramsJson = "{}";
80
80
  try {
81
- paramsJson = gson.toJson(klarnaProductEvent.getParams());
81
+ paramsJson = ParserUtil.INSTANCE.toJson(DynamicMapSerializer.INSTANCE, klarnaProductEvent.getParams());
82
82
  } catch (Exception ignored) {
83
83
  }
84
84
  String finalParamsJson = paramsJson;
@@ -0,0 +1,229 @@
1
+ package com.klarna.mobile.sdk.reactnative.common.serializer
2
+
3
+ import com.klarna.mobile.sdk.reactnative.common.util.ParserUtil
4
+ import kotlinx.serialization.Serializable
5
+ import kotlinx.serialization.json.Json
6
+ import org.junit.Assert.assertEquals
7
+ import org.junit.Test
8
+ import kotlin.test.assertContentEquals
9
+
10
+ class DynamicMapSerializerTest {
11
+
12
+ private val json = Json { ignoreUnknownKeys = true }
13
+
14
+ @Test
15
+ fun `test serialization of primitive values`() {
16
+ val map = mapOf(
17
+ "nullValue" to null,
18
+ "booleanValue" to true,
19
+ "intValue" to 42,
20
+ "longValue" to 123456789L,
21
+ "floatValue" to 3.14f,
22
+ "doubleValue" to 2.71828,
23
+ "stringValue" to "hello",
24
+ "charValue" to 'A'
25
+ )
26
+
27
+ val jsonString = json.encodeToString(DynamicMapSerializer, map)
28
+ val expectedJson =
29
+ """{"nullValue":null,"booleanValue":true,"intValue":42,"longValue":123456789,"floatValue":3.14,"doubleValue":2.71828,"stringValue":"hello","charValue":"A"}"""
30
+
31
+ assertEquals(expectedJson, jsonString)
32
+ }
33
+
34
+ @Test
35
+ fun `test deserialization of primitive values`() {
36
+ val jsonString =
37
+ """{"nullValue":null,"booleanValue":true,"intValue":42,"longValue":123456789,"floatValue":3.14,"doubleValue":2.71828,"stringValue":"hello"}"""
38
+
39
+ val map = json.decodeFromString(DynamicMapSerializer, jsonString)
40
+
41
+ assertEquals(null, map["nullValue"])
42
+ assertEquals(true, map["booleanValue"])
43
+ assertEquals(42L, map["intValue"])
44
+ assertEquals(123456789L, map["longValue"])
45
+ assertEquals(3.14, map["floatValue"])
46
+ assertEquals(2.71828, map["doubleValue"])
47
+ assertEquals("hello", map["stringValue"])
48
+ }
49
+
50
+ @Test
51
+ fun `test serialization of nested maps`() {
52
+ val nestedMap = mapOf(
53
+ "inner" to mapOf(
54
+ "key1" to "value1",
55
+ "key2" to 42
56
+ )
57
+ )
58
+
59
+ val jsonString = json.encodeToString(DynamicMapSerializer, nestedMap)
60
+ val expectedJson = """{"inner":{"key1":"value1","key2":42}}"""
61
+
62
+ assertEquals(expectedJson, jsonString)
63
+ }
64
+
65
+ @Suppress("UNCHECKED_CAST")
66
+ @Test
67
+ fun `test deserialization of nested maps`() {
68
+ val jsonString = """{"outer":{"inner":{"key1":"value1","key2":42}}}"""
69
+
70
+ val map = json.decodeFromString(DynamicMapSerializer, jsonString)
71
+
72
+ val outer = map["outer"] as Map<String, Any?>
73
+ val inner = outer["inner"] as Map<String, Any?>
74
+
75
+ assertEquals("value1", inner["key1"])
76
+ assertEquals(42L, inner["key2"])
77
+ }
78
+
79
+ @Test
80
+ fun `test serialization of collections`() {
81
+ val map = mapOf(
82
+ "list" to listOf(1, 2, 3),
83
+ "mixedList" to listOf(1, "two", 3.0)
84
+ )
85
+
86
+ val jsonString = json.encodeToString(DynamicMapSerializer, map)
87
+ val expectedJson = """{"list":[1,2,3],"mixedList":[1,"two",3.0]}"""
88
+
89
+ assertEquals(expectedJson, jsonString)
90
+ }
91
+
92
+ @Suppress("UNCHECKED_CAST")
93
+ @Test
94
+ fun `test deserialization of collections`() {
95
+ val jsonString = """{"list":[1,2,3],"mixedList":[1,"two",3.0]}"""
96
+
97
+ val map = json.decodeFromString(DynamicMapSerializer, jsonString)
98
+
99
+ val list = map["list"] as List<Long>
100
+ val mixedList = map["mixedList"] as Collection<Any?>
101
+
102
+ assertContentEquals(listOf(1L, 2L, 3L), list)
103
+ assertEquals(1L, mixedList.elementAt(0))
104
+ assertEquals("two", mixedList.elementAt(1))
105
+ assertEquals(3.0, mixedList.elementAt(2))
106
+ }
107
+
108
+ @Test
109
+ fun `test serialization of arrays`() {
110
+ val map = mapOf(
111
+ "array" to arrayOf(1, 2, 3)
112
+ )
113
+
114
+ val jsonString = json.encodeToString(DynamicMapSerializer, map)
115
+ val expectedJson = """{"array":[1,2,3]}"""
116
+
117
+ assertEquals(expectedJson, jsonString)
118
+ }
119
+
120
+ @Test
121
+ fun `test serialization of complex nested structures`() {
122
+ val complex = mapOf(
123
+ "name" to "Complex",
124
+ "properties" to mapOf(
125
+ "nested" to listOf(
126
+ mapOf("id" to 1, "value" to "first"),
127
+ mapOf("id" to 2, "value" to "second")
128
+ )
129
+ ),
130
+ "tags" to arrayOf("important", "test")
131
+ )
132
+
133
+ val jsonString = json.encodeToString(DynamicMapSerializer, complex)
134
+ val expectedJson =
135
+ """{"name":"Complex","properties":{"nested":[{"id":1,"value":"first"},{"id":2,"value":"second"}]},"tags":["important","test"]}"""
136
+
137
+ assertEquals(expectedJson, jsonString)
138
+ }
139
+
140
+ @Suppress("UNCHECKED_CAST")
141
+ @Test
142
+ fun `test serialization and deserialization of data classes`() {
143
+ // Define a data class for testing
144
+ data class TestDataClass2(
145
+ val street: String,
146
+ val city: String,
147
+ val zipCode: String
148
+ )
149
+
150
+ data class TestDataClass1(
151
+ val name: String,
152
+ val age: Int,
153
+ val address: TestDataClass2
154
+ )
155
+
156
+ // Create test data
157
+ val address = TestDataClass2("123 Main St", "Anytown", "12345")
158
+ val person = TestDataClass1("John Doe", 30, address)
159
+
160
+ // Create a map with the data class
161
+ val map = mapOf(
162
+ "person" to person,
163
+ "simpleValue" to 42
164
+ )
165
+
166
+ // Serialize
167
+ val jsonString = json.encodeToString(DynamicMapSerializer, map)
168
+
169
+ // Expected JSON structure
170
+ val expectedJson =
171
+ """{"person":{"name":"John Doe","age":30,"address":{"street":"123 Main St","city":"Anytown","zipCode":"12345"}},"simpleValue":42}"""
172
+
173
+ // Verify serialization
174
+ assertEquals(ParserUtil.parse(expectedJson), ParserUtil.parse(jsonString))
175
+
176
+ // Deserialize
177
+ val deserializedMap = json.decodeFromString(DynamicMapSerializer, jsonString)
178
+
179
+ // Verify deserialization
180
+ assertEquals(42L, deserializedMap["simpleValue"])
181
+
182
+ // Check the nested structure
183
+ val deserializedPerson = deserializedMap["person"] as Map<String, Any?>
184
+ assertEquals("John Doe", deserializedPerson["name"])
185
+ assertEquals(30L, deserializedPerson["age"])
186
+
187
+ val deserializedAddress = deserializedPerson["address"] as Map<String, Any?>
188
+ assertEquals("123 Main St", deserializedAddress["street"])
189
+ assertEquals("Anytown", deserializedAddress["city"])
190
+ assertEquals("12345", deserializedAddress["zipCode"])
191
+ }
192
+
193
+ @Test
194
+ fun `test serialization and deserialization of serializable objects`() {
195
+ // Define a serializable class
196
+ @Serializable
197
+ data class SerializableUser(
198
+ val id: Int,
199
+ val username: String
200
+ )
201
+
202
+ // Create test data with serializable object
203
+ val user = SerializableUser(id = 1001, username = "testuser")
204
+ val map = mapOf(
205
+ "user" to user,
206
+ "timestamp" to 1634567890L
207
+ )
208
+
209
+ // Serialize
210
+ val jsonString = json.encodeToString(DynamicMapSerializer, map)
211
+
212
+ // Expected JSON structure
213
+ val expectedJson = """{"user":{"id":1001,"username":"testuser"},"timestamp":1634567890}"""
214
+
215
+ // Verify serialization
216
+ assertEquals(ParserUtil.parse(expectedJson), ParserUtil.parse(jsonString))
217
+
218
+ // Deserialize
219
+ val deserializedMap = json.decodeFromString(DynamicMapSerializer, jsonString)
220
+
221
+ // Verify deserialization
222
+ assertEquals(1634567890L, deserializedMap["timestamp"])
223
+
224
+ // Check the serializable object
225
+ val deserializedUser = deserializedMap["user"] as Map<String, Any?>
226
+ assertEquals(1001L, deserializedUser["id"])
227
+ assertEquals("testuser", deserializedUser["username"])
228
+ }
229
+ }
@@ -0,0 +1,39 @@
1
+ package com.klarna.mobile.sdk.reactnative.common.util
2
+
3
+ import kotlinx.serialization.SerialName
4
+ import kotlinx.serialization.Serializable
5
+ import kotlinx.serialization.SerializationException
6
+ import org.junit.Test
7
+ import kotlin.test.assertEquals
8
+ import kotlin.test.assertFailsWith
9
+ import kotlin.test.assertNotNull
10
+
11
+ internal class ParserUtilTest {
12
+ @Test
13
+ fun `test gson is not null`() {
14
+ assertNotNull(ParserUtil.json)
15
+ }
16
+
17
+ @Test
18
+ fun `test toJson success`() {
19
+ val serialized = ParserUtil.toJson(TestData("test"))
20
+ assertEquals("{\"data\":\"test\"}", serialized)
21
+ }
22
+
23
+ @Test
24
+ fun `test toJson fail`() {
25
+ val testData = NonSerializableData("")
26
+ assertFailsWith(SerializationException::class, "test") {
27
+ ParserUtil.toJson(testData)
28
+ }
29
+ }
30
+
31
+ @Serializable
32
+ private data class TestData(
33
+ @SerialName("data") val data: String,
34
+ )
35
+
36
+ private data class NonSerializableData(
37
+ val data: String,
38
+ )
39
+ }
@@ -6,6 +6,7 @@
6
6
  //
7
7
 
8
8
  #import <Foundation/Foundation.h>
9
+ #import <KlarnaMobileSDK/KlarnaMobileSDK.h>
9
10
  #import "KlarnaMobileSDK/KlarnaMobileSDK-Swift.h"
10
11
  #import <React/RCTBridgeModule.h>
11
12
 
@@ -6,6 +6,8 @@
6
6
  //
7
7
 
8
8
  #import "KlarnaSignInData.h"
9
+ #import <KlarnaMobileSDK/KlarnaMobileSDK.h>
10
+ #import <KlarnaMobileSDK/KlarnaMobileSDK-Swift.h>
9
11
 
10
12
  @implementation KlarnaSignInData
11
13
 
@@ -8,6 +8,7 @@
8
8
  #import "KlarnaSignInModuleImpl.h"
9
9
  #import "../common/RNMobileSDKUtils.h"
10
10
  #import <AuthenticationServices/AuthenticationServices.h>
11
+ #import <KlarnaMobileSDK/KlarnaMobileSDK.h>
11
12
  #import "KlarnaMobileSDK/KlarnaMobileSDK-Swift.h"
12
13
  #import <React/RCTLog.h>
13
14
  #import "KlarnaSignInData.h"
@@ -9,6 +9,7 @@
9
9
  #import "../KlarnaCheckoutViewWrapper.h"
10
10
  #import "../../common/RNMobileSDKUtils.h"
11
11
  #import "RCTFabricComponentsPlugins.h"
12
+ #import <KlarnaMobileSDK/KlarnaMobileSDK.h>
12
13
  #import <KlarnaMobileSDK/KlarnaMobileSDK-Swift.h>
13
14
 
14
15
  using namespace facebook::react;
@@ -3,6 +3,7 @@
3
3
  #import "../KlarnaStandaloneWebViewWrapper.h"
4
4
 
5
5
  #import <AVFoundation/AVFoundation.h>
6
+ #import <KlarnaMobileSDK/KlarnaMobileSDK.h>
6
7
  #import <KlarnaMobileSDK/KlarnaMobileSDK-Swift.h>
7
8
  #import <React/RCTLog.h>
8
9
 
@@ -3,6 +3,7 @@
3
3
  #import "../PaymentViewWrapper.h"
4
4
 
5
5
  #import <AVFoundation/AVFoundation.h>
6
+ #import <KlarnaMobileSDK/KlarnaMobileSDK.h>
6
7
  #import <KlarnaMobileSDK/KlarnaMobileSDK-Swift.h>
7
8
  #import <React/RCTLog.h>
8
9
 
@@ -3,6 +3,7 @@
3
3
  #import <React/RCTLog.h>
4
4
  #import "../KlarnaCheckoutViewWrapper.h"
5
5
  #import "../../common/RNMobileSDKUtils.h"
6
+ #import <KlarnaMobileSDK/KlarnaMobileSDK.h>
6
7
  #import <KlarnaMobileSDK/KlarnaMobileSDK-Swift.h>
7
8
 
8
9
  @interface KlarnaCheckoutViewWrapper () <KlarnaEventHandler, KlarnaSizingDelegate>
@@ -2,6 +2,7 @@
2
2
 
3
3
  #import "../KlarnaStandaloneWebViewWrapper.h"
4
4
 
5
+ #import <KlarnaMobileSDK/KlarnaMobileSDK.h>
5
6
  #import <KlarnaMobileSDK/KlarnaMobileSDK-Swift.h>
6
7
  #import <React/RCTLog.h>
7
8
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  #import "../PaymentViewWrapper.h"
4
4
 
5
+ #import <KlarnaMobileSDK/KlarnaMobileSDK.h>
5
6
  #import <KlarnaMobileSDK/KlarnaMobileSDK-Swift.h>
6
7
  #import <React/RCTLog.h>
7
8
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "react-native-klarna-inapp-sdk",
3
3
  "title": "Klarna Mobile SDK React Native",
4
- "version": "2.4.3",
4
+ "version": "2.4.5",
5
5
  "description": "This library wraps Klarna Mobile SDK and exposes its functionality as React Native components.",
6
6
  "main": "lib/commonjs/index",
7
7
  "module": "lib/module/index",
@@ -48,5 +48,5 @@ Pod::Spec.new do |s|
48
48
  end
49
49
  end
50
50
 
51
- s.dependency 'KlarnaMobileSDK', '2.6.29'
51
+ s.dependency 'KlarnaMobileSDK', '2.7.2'
52
52
  end
@@ -1,36 +0,0 @@
1
- package com.klarna.mobile.sdk.reactnative.common.util;
2
-
3
- import android.util.Log;
4
-
5
- import com.google.gson.Gson;
6
- import com.google.gson.GsonBuilder;
7
-
8
- public class ParserUtil {
9
- public static final Gson gson = new GsonBuilder().create();
10
-
11
- public static String toJson(Object obj) {
12
- return gson.toJson(obj);
13
- }
14
-
15
- public static String toJsonSafe(Object obj) {
16
- try {
17
- return gson.toJson(obj);
18
- } catch (Throwable t) {
19
- Log.e(ParserUtil.class.getSimpleName(), "Failed to serialize object to string with Gson: " + t.getMessage());
20
- return null;
21
- }
22
- }
23
-
24
- public static <T> T fromJson(String json, Class<T> cls) {
25
- return gson.fromJson(json, cls);
26
- }
27
-
28
- public static <T> T fromJsonSafe(String json, Class<T> cls) {
29
- try {
30
- return gson.fromJson(json, cls);
31
- } catch (Throwable t) {
32
- Log.e(ParserUtil.class.getSimpleName(), "Failed to deserialize object from string with Gson: " + t.getMessage());
33
- return null;
34
- }
35
- }
36
- }