react-native-persona 2.32.1 → 2.32.3

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.
@@ -2,7 +2,7 @@ require 'json'
2
2
 
3
3
  package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
4
4
 
5
- persona_sdk_version = '2.41.2'
5
+ persona_sdk_version = '2.41.4'
6
6
 
7
7
  Pod::Spec.new do |s|
8
8
  s.name = 'RNPersonaInquiry2'
@@ -3,6 +3,8 @@ def DEFAULT_MIN_SDK_VERSION = 21
3
3
  def DEFAULT_TARGET_SDK_VERSION = 35
4
4
 
5
5
  buildscript {
6
+ ext.kotlin_version = '2.1.21'
7
+
6
8
  if (project == rootProject) {
7
9
  repositories {
8
10
  google()
@@ -11,11 +13,13 @@ buildscript {
11
13
 
12
14
  dependencies {
13
15
  classpath 'com.android.tools.build:gradle:8.1.1'
16
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
14
17
  }
15
18
  }
16
19
  }
17
20
 
18
21
  apply plugin: 'com.android.library'
22
+ apply plugin: 'kotlin-android'
19
23
 
20
24
  def safeExtGet(prop, fallback) {
21
25
  rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
@@ -40,8 +44,11 @@ android {
40
44
  disable 'GradleCompatible'
41
45
  }
42
46
  compileOptions {
43
- sourceCompatibility JavaVersion.VERSION_1_8
44
- targetCompatibility JavaVersion.VERSION_1_8
47
+ sourceCompatibility JavaVersion.VERSION_17
48
+ targetCompatibility JavaVersion.VERSION_17
49
+ }
50
+ kotlinOptions {
51
+ jvmTarget = '17'
45
52
  }
46
53
  dexOptions {
47
54
  preDexLibraries = false
@@ -65,6 +72,9 @@ dependencies {
65
72
  implementation("com.facebook.react:react-android:+")
66
73
 
67
74
  // NB: be sure to bump `nfc-impl` in example/android/app/build.gradle as well
68
- implementation 'com.withpersona.sdk2:inquiry:2.32.1'
75
+ implementation 'com.withpersona.sdk2:inquiry:2.32.3'
69
76
  implementation("androidx.fragment:fragment:1.8.6")
77
+
78
+ // Kotlin
79
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
70
80
  }
@@ -0,0 +1,103 @@
1
+ package com.withpersona.sdk2.reactnative
2
+
3
+ import android.os.Bundle
4
+ import android.view.LayoutInflater
5
+ import android.view.View
6
+ import android.view.ViewGroup
7
+ import android.widget.FrameLayout
8
+ import androidx.fragment.app.Fragment
9
+ import androidx.lifecycle.lifecycleScope
10
+ import com.withpersona.sdk2.inquiry.ExperimentalInlineApi
11
+ import com.withpersona.sdk2.inquiry.inline_inquiry.InlineInquiryController
12
+ import com.withpersona.sdk2.inquiry.inline_inquiry.InlineInquiryScreen
13
+ import com.withpersona.sdk2.inquiry.types.DEFAULT_REQUEST_KEY
14
+ import kotlinx.coroutines.launch
15
+
16
+ /**
17
+ * Wrapper fragment that acts as a parent for [InquiryFragment] and implements
18
+ * [InlineInquiryController] to receive event callbacks from the child [InquiryFragment].
19
+ */
20
+ @OptIn(ExperimentalInlineApi::class)
21
+ class InlineInquiryWrapperFragment : Fragment(), InlineInquiryController {
22
+
23
+ companion object {
24
+ private const val ARG_REQUEST_KEY = "pi2_rn_request_key"
25
+
26
+ const val ARG_EVENT = "pi2_rn_event"
27
+
28
+ fun newInstance(
29
+ requestKey: String,
30
+ inquiryFragment: Fragment,
31
+ ): InlineInquiryWrapperFragment = InlineInquiryWrapperFragment().apply {
32
+ arguments = Bundle().apply {
33
+ putString(ARG_REQUEST_KEY, requestKey)
34
+ }
35
+
36
+ // This is a hack in order to let InlineInquiryWrapperFragment launch the InquiryFragment.
37
+ // This is very difficult to do without code changes to the SDK side. This hack should
38
+ // not cause any issues since the fragment should only need to be launched once.
39
+ // On kill/restore, the fragment state should be saved by the fragment manager.
40
+ this.inquiryFragment = inquiryFragment
41
+ }
42
+ }
43
+
44
+ private var inlineInquiryScreen: InlineInquiryScreen? = null
45
+ private var inquiryFragment: Fragment? = null
46
+ private var requestKey: String? = null
47
+
48
+ override fun onCreateView(
49
+ inflater: LayoutInflater,
50
+ container: ViewGroup?,
51
+ savedInstanceState: Bundle?
52
+ ): View {
53
+ return FrameLayout(requireContext()).apply {
54
+ id = R.id.pi2_rn_wrapper_fragment_frame_layout
55
+ layoutParams = ViewGroup.LayoutParams(
56
+ ViewGroup.LayoutParams.MATCH_PARENT,
57
+ ViewGroup.LayoutParams.MATCH_PARENT
58
+ )
59
+ }
60
+ }
61
+
62
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
63
+ super.onViewCreated(view, savedInstanceState)
64
+
65
+ requestKey = arguments?.getString(ARG_REQUEST_KEY)
66
+
67
+ childFragmentManager.setFragmentResultListener(DEFAULT_REQUEST_KEY, viewLifecycleOwner) { _, result ->
68
+ parentFragmentManager.setFragmentResult(DEFAULT_REQUEST_KEY, result)
69
+ }
70
+
71
+ // Only add the fragment on first launch. On save/restore, the fragment manager should
72
+ // restore the fragment for us.
73
+ if (savedInstanceState == null) {
74
+ inquiryFragment?.let { fragment ->
75
+ childFragmentManager
76
+ .beginTransaction()
77
+ .add(R.id.pi2_rn_wrapper_fragment_frame_layout, fragment)
78
+ .commit()
79
+ }
80
+ }
81
+ }
82
+
83
+ override fun onAttached(inlineInquiryScreen: InlineInquiryScreen) {
84
+ this.inlineInquiryScreen = inlineInquiryScreen
85
+ viewLifecycleOwner.lifecycleScope.launch {
86
+ inlineInquiryScreen.eventFlow.collect {
87
+ val requestKey = requestKey
88
+ if (requestKey != null) {
89
+ parentFragmentManager.setFragmentResult(
90
+ requestKey,
91
+ Bundle().apply {
92
+ putParcelable(ARG_EVENT, it)
93
+ }
94
+ )
95
+ }
96
+ }
97
+ }
98
+ }
99
+
100
+ override fun onDetached() {
101
+ inlineInquiryScreen = null
102
+ }
103
+ }
@@ -0,0 +1,25 @@
1
+ package com.withpersona.sdk2.reactnative
2
+
3
+ import com.facebook.react.bridge.Arguments.createMap
4
+ import com.facebook.react.bridge.ReactContext
5
+ import com.facebook.react.uimanager.events.RCTEventEmitter
6
+ import com.withpersona.sdk2.inquiry.ExperimentalInlineApi
7
+ import com.withpersona.sdk2.inquiry.inline_inquiry.InquiryEvent
8
+
9
+ class InquiryEventEmitter(
10
+ private val reactContext: ReactContext,
11
+ private val targetId: Int,
12
+ ) {
13
+
14
+ @OptIn(ExperimentalInlineApi::class)
15
+ fun emitEvent(inquiryEvent: InquiryEvent) {
16
+ val map = InquiryUtils.inquiryEventToMap(inquiryEvent)
17
+
18
+ if (map != null) {
19
+ val params = createMap()
20
+ params.putMap("event", map)
21
+ reactContext.getJSModule<RCTEventEmitter?>(RCTEventEmitter::class.java)
22
+ .receiveEvent(targetId, "onEvent", params)
23
+ }
24
+ }
25
+ }
@@ -18,10 +18,10 @@ import com.withpersona.sdk2.inquiry.InquiryResponse;
18
18
 
19
19
  import java.util.Map;
20
20
 
21
- public class InquiryEventEmitter {
21
+ public class InquiryResultEmitter {
22
22
  @NonNull private final ReactContext reactContext;
23
23
 
24
- public InquiryEventEmitter(@NonNull ReactContext reactContext) {
24
+ public InquiryResultEmitter(@NonNull ReactContext reactContext) {
25
25
  this.reactContext = reactContext;
26
26
  }
27
27
 
@@ -1,6 +1,8 @@
1
1
  package com.withpersona.sdk2.reactnative;
2
2
 
3
+ import androidx.annotation.NonNull;
3
4
  import androidx.annotation.Nullable;
5
+ import androidx.annotation.OptIn;
4
6
 
5
7
  import com.facebook.react.bridge.Arguments;
6
8
  import com.facebook.react.bridge.ReadableArray;
@@ -9,12 +11,14 @@ import com.facebook.react.bridge.WritableArray;
9
11
  import com.facebook.react.bridge.WritableMap;
10
12
  import com.withpersona.sdk2.inquiry.ClientThemeSource;
11
13
  import com.withpersona.sdk2.inquiry.Environment;
14
+ import com.withpersona.sdk2.inquiry.ExperimentalInlineApi;
12
15
  import com.withpersona.sdk2.inquiry.Fields;
13
16
  import com.withpersona.sdk2.inquiry.Inquiry;
14
17
  import com.withpersona.sdk2.inquiry.InquiryBuilder;
15
18
  import com.withpersona.sdk2.inquiry.InquiryTemplateBuilder;
16
19
  import com.withpersona.sdk2.inquiry.ServerThemeSource;
17
20
  import com.withpersona.sdk2.inquiry.StyleVariant;
21
+ import com.withpersona.sdk2.inquiry.inline_inquiry.InquiryEvent;
18
22
  import com.withpersona.sdk2.inquiry.types.collected_data.CollectedData;
19
23
  import com.withpersona.sdk2.inquiry.types.collected_data.DocumentFile;
20
24
  import com.withpersona.sdk2.inquiry.types.collected_data.GovernmentIdCapture;
@@ -260,6 +264,28 @@ class InquiryUtils {
260
264
  return collectedDataMap;
261
265
  }
262
266
 
267
+ @OptIn(markerClass = ExperimentalInlineApi.class)
268
+ @Nullable
269
+ protected static ReadableMap inquiryEventToMap(@NonNull InquiryEvent inquiryEvent) {
270
+ WritableMap inquiryEventMap = Arguments.createMap();
271
+
272
+ if (inquiryEvent instanceof InquiryEvent.StartEvent) {
273
+ InquiryEvent.StartEvent start = (InquiryEvent.StartEvent) inquiryEvent;
274
+ inquiryEventMap.putString("type", "start");
275
+ inquiryEventMap.putString("inquiryId", start.getInquiryId());
276
+ inquiryEventMap.putString("sessionToken", start.getSessionToken());
277
+ } else if (inquiryEvent instanceof InquiryEvent.PageChange) {
278
+ InquiryEvent.PageChange pageChange = (InquiryEvent.PageChange) inquiryEvent;
279
+ inquiryEventMap.putString("type", "page_change");
280
+ inquiryEventMap.putString("name", pageChange.getName());
281
+ inquiryEventMap.putString("path", pageChange.getPath());
282
+ } else {
283
+ return null;
284
+ }
285
+
286
+ return inquiryEventMap;
287
+ }
288
+
263
289
  private static Environment environmentFromString(@Nullable String environment) {
264
290
  if (environment == null) {
265
291
  return null;
@@ -1,5 +1,7 @@
1
1
  package com.withpersona.sdk2.reactnative;
2
2
 
3
+ import static com.withpersona.sdk2.reactnative.InquiryUtils.inquiryEventToMap;
4
+
3
5
  import android.app.Activity;
4
6
  import android.content.Intent;
5
7
 
@@ -60,7 +62,7 @@ public class PersonaInquiryModule2 extends ReactContextBaseJavaModule
60
62
  if (requestCode == PERSONA_INQUIRY_REQUEST_CODE) {
61
63
  InquiryResponse response = Inquiry.onActivityResult(data);
62
64
 
63
- new InquiryEventEmitter(reactContext).emitResponse(response);
65
+ new InquiryResultEmitter(reactContext).emitResponse(response);
64
66
  }
65
67
  }
66
68
 
@@ -123,28 +125,6 @@ public class PersonaInquiryModule2 extends ReactContextBaseJavaModule
123
125
  });
124
126
  }
125
127
 
126
- @OptIn(markerClass = ExperimentalInlineApi.class)
127
- @Nullable
128
- private ReadableMap inquiryEventToMap(@NonNull InquiryEvent inquiryEvent) {
129
- WritableMap inquiryEventMap = Arguments.createMap();
130
-
131
- if (inquiryEvent instanceof InquiryEvent.StartEvent) {
132
- InquiryEvent.StartEvent start = (InquiryEvent.StartEvent) inquiryEvent;
133
- inquiryEventMap.putString("type", "start");
134
- inquiryEventMap.putString("inquiryId", start.getInquiryId());
135
- inquiryEventMap.putString("sessionToken", start.getSessionToken());
136
- } else if (inquiryEvent instanceof InquiryEvent.PageChange) {
137
- InquiryEvent.PageChange pageChange = (InquiryEvent.PageChange) inquiryEvent;
138
- inquiryEventMap.putString("type", "page_change");
139
- inquiryEventMap.putString("name", pageChange.getName());
140
- inquiryEventMap.putString("path", pageChange.getPath());
141
- } else {
142
- return null;
143
- }
144
-
145
- return inquiryEventMap;
146
- }
147
-
148
128
  @Nullable
149
129
  private DeviceEventManagerModule.RCTDeviceEventEmitter getJsModule() {
150
130
  try {
@@ -2,8 +2,8 @@ package com.withpersona.sdk2.reactnative;
2
2
 
3
3
  import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
4
4
  import static com.withpersona.sdk2.inquiry.types.ConstsKt.DEFAULT_REQUEST_KEY;
5
+ import static com.withpersona.sdk2.reactnative.InlineInquiryWrapperFragment.ARG_EVENT;
5
6
 
6
- import android.graphics.Color;
7
7
  import android.view.Choreographer;
8
8
  import android.view.View;
9
9
  import android.view.ViewGroup;
@@ -14,7 +14,6 @@ import androidx.annotation.Nullable;
14
14
  import androidx.fragment.app.Fragment;
15
15
  import androidx.fragment.app.FragmentActivity;
16
16
 
17
- import com.facebook.react.bridge.ReactApplicationContext;
18
17
  import com.facebook.react.bridge.ReadableArray;
19
18
  import com.facebook.react.bridge.ReadableMap;
20
19
  import com.facebook.react.common.MapBuilder;
@@ -23,6 +22,7 @@ import com.facebook.react.uimanager.ViewGroupManager;
23
22
  import com.facebook.react.uimanager.annotations.ReactProp;
24
23
  import com.withpersona.sdk2.inquiry.Inquiry;
25
24
  import com.withpersona.sdk2.inquiry.InquiryResponse;
25
+ import com.withpersona.sdk2.inquiry.inline_inquiry.InquiryEvent;
26
26
 
27
27
  import java.util.Map;
28
28
 
@@ -107,6 +107,12 @@ class PersonaInquiryViewManager extends ViewGroupManager<FrameLayout> {
107
107
  "phasedRegistrationNames",
108
108
  MapBuilder.of("bubbled", "onError")
109
109
  )
110
+ ).put(
111
+ "onEvent",
112
+ MapBuilder.of(
113
+ "phasedRegistrationNames",
114
+ MapBuilder.of("bubbled", "onEvent")
115
+ )
110
116
  ).build();
111
117
  }
112
118
 
@@ -131,12 +137,12 @@ class PersonaInquiryViewManager extends ViewGroupManager<FrameLayout> {
131
137
  return;
132
138
  }
133
139
 
134
- Fragment fragment = inquiry
140
+ Fragment inquiryFragment = inquiry
135
141
  .buildInlineInquiry()
136
142
  .build()
137
143
  .createFragment();
138
144
 
139
- if (fragment == null) {
145
+ if (inquiryFragment == null) {
140
146
  return;
141
147
  }
142
148
 
@@ -146,15 +152,31 @@ class PersonaInquiryViewManager extends ViewGroupManager<FrameLayout> {
146
152
  return;
147
153
  }
148
154
 
155
+ final String requestKey = "pi2_rn_inquiry_" + reactNativeViewId;
156
+ InquiryEventEmitter inquiryEventEmitter = new InquiryEventEmitter(reactContext, root.getId());
157
+
149
158
  activity.getSupportFragmentManager()
150
- .setFragmentResultListener(DEFAULT_REQUEST_KEY, activity, (requestKey, result) -> {
159
+ .setFragmentResultListener(DEFAULT_REQUEST_KEY, activity, (reqKey, result) -> {
151
160
  InquiryResponse response = Inquiry.extractInquiryResponseFromBundle(result, reactContext);
152
- new InquiryEventEmitter(reactContext).emitResponse(response, root);
161
+ new InquiryResultEmitter(reactContext).emitResponse(response, root);
153
162
  });
163
+ activity.getSupportFragmentManager()
164
+ .setFragmentResultListener(requestKey, activity, (reqKey, result) -> {
165
+ InquiryEvent event = result.getParcelable(ARG_EVENT);
166
+
167
+ if (event != null) {
168
+ inquiryEventEmitter.emitEvent(event);
169
+ }
170
+ });
171
+
172
+ Fragment wrapperFragment = InlineInquiryWrapperFragment.Companion.newInstance(
173
+ requestKey,
174
+ inquiryFragment
175
+ );
154
176
 
155
177
  activity.getSupportFragmentManager()
156
178
  .beginTransaction()
157
- .replace(reactNativeViewId, fragment, String.valueOf(reactNativeViewId))
179
+ .replace(reactNativeViewId, wrapperFragment, String.valueOf(reactNativeViewId))
158
180
  .commit();
159
181
  parentView.requestLayout();
160
182
  }
@@ -1,4 +1,5 @@
1
1
  <?xml version="1.0" encoding="utf-8"?>
2
2
  <resources>
3
3
  <item name="pi2_rn_inquiry_options" type="id" />
4
+ <item name="pi2_rn_wrapper_fragment_frame_layout" type="id" />
4
5
  </resources>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "react-native-persona",
3
3
  "title": "React Native Persona",
4
- "version": "2.32.1",
4
+ "version": "2.32.3",
5
5
  "description": "Launch a mobile native implementation of the Persona inquiry flow from React Native.",
6
6
  "homepage": "https://docs.withpersona.com/docs/react-native-sdk-integration",
7
7
  "bugs": "https://github.com/persona-id/persona-inquiry-sdk-public",