Skip to content

Commit d0dab5a

Browse files
committed
Merge branch 'main' into DIA-5675-programmatic-reject-all-feature
# Conflicts: # src/index.tsx
2 parents e1d97b5 + d773ed2 commit d0dab5a

File tree

16 files changed

+140
-105
lines changed

16 files changed

+140
-105
lines changed

README.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ In the sections below, we will review each of the steps in more detail:
3636
In your app, you can setup the SPConsent manager in a external file or on your app. In the example below we use `useRef`
3737
to keep a reference of the `SPConsentManager`.
3838

39-
> It is important to notice that we wrap the initialisation of `SPConsentManager` in a `useEffect` and call `consentManager.current?.dispose()` to avoid memory leaks.
39+
> It is important to notice that we wrap the initialisation of `SPConsentManager` in a `useEffect` and set its reference to `null` to avoid memory leaks.
4040
4141
```ts
4242
const consentManager = useRef<SPConsentManager | null>();
@@ -52,7 +52,7 @@ useEffect(() => {
5252
);
5353

5454
return () => {
55-
consentManager.current?.dispose();
55+
consentManager.current = null;
5656
};
5757
}
5858
```
@@ -88,6 +88,7 @@ Refer to the table below regarding the different campaigns that can be implement
8888
| `onAction(callback: (action: string) => {})` | Called when the user takes an action (e.g. Accept All) within the consent message. `action: string` is going to be replaced with an enum. |
8989
| `onSPUIFinished(callback: () => {})` | Called when the native SDKs is done removing the consent UI from the foreground. |
9090
| `onFinished(callback: () => {})` | Called when all UI and network processes are finished. User consent is stored on the local storage of each platform (`UserDefaults` for iOS and `SharedPrefs` for Android). And it is safe to retrieve consent data with `getUserData` |
91+
| `onMessageInactivityTimeout(callback: () => {})` | Called when the user becomes inactive while viewing a consent message. This allows your app to respond to user inactivity events. |
9192
| `onError(callback: (description: string) => {})` | Called if something goes wrong. |
9293
9394
### Call `loadMessages`
@@ -239,6 +240,8 @@ export default function App() {
239240
// is disabled in the Sourcepoint dashboard
240241
language: SPMessageLanguage.ENGLISH,
241242
messageTimeoutInSeconds: 20,
243+
// Allows Android users to dismiss the consent message on back press. True by default. Set it to false if you wish to prevent this users from dismissing the message on back press.
244+
androidDismissMessageOnBackPress: true,
242245
}
243246
);
244247

@@ -255,6 +258,9 @@ export default function App() {
255258
consentManager.current?.onAction(({ actionType }) => {
256259
console.log(`User took action ${actionType}`)
257260
});
261+
consentManager.current?.onMessageInactivityTimeout(() => {
262+
console.log("User became inactive")
263+
});
258264
consentManager.current?.onError(console.error)
259265

260266
consentManager.current?.loadMessage();

ReactNativeCmp.podspec

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@ Pod::Spec.new do |s|
1212
s.license = package["license"]
1313
s.authors = package["author"]
1414

15+
s.static_framework = true
16+
1517
s.platforms = { :ios => min_ios_version_supported }
1618
s.source = { :git => "https://github.com/SourcePointUSA/react-native-sourcepoint-cmp.git", :tag => "#{s.version}" }
1719

18-
s.dependency "ConsentViewController", "7.11.1"
20+
s.dependency "ConsentViewController", "7.12.1"
1921
s.source_files = "ios/**/*.{h,m,mm,cpp,swift}"
2022
s.private_header_files = "ios/**/*.h"
2123

android/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ dependencies {
7777
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3"
7878
implementation "org.jetbrains.kotlinx:kotlinx-datetime:0.6.1"
7979

80-
implementation "com.sourcepoint.cmplibrary:cmplibrary:7.15.2"
80+
implementation "com.sourcepoint.cmplibrary:cmplibrary:7.15.4"
8181
}
8282

8383
react {

android/src/main/java/com/sourcepoint/reactnativecmp/ReactNativeCmpModule.kt

Lines changed: 26 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,13 @@
11
package com.sourcepoint.reactnativecmp
22

33
import android.view.View
4-
import com.facebook.react.bridge.Arguments.createMap
54
import com.facebook.react.bridge.Callback
65
import com.facebook.react.bridge.Promise
76
import com.facebook.react.bridge.ReactApplicationContext
8-
import com.facebook.react.bridge.ReactMethod
9-
import com.facebook.react.bridge.ReadableMap
107
import com.facebook.react.bridge.ReadableArray
11-
import com.facebook.react.module.annotations.ReactModule
12-
import com.sourcepoint.cmplibrary.NativeMessageController
8+
import com.facebook.react.bridge.ReadableMap
139
import com.sourcepoint.cmplibrary.SpClient
1410
import com.sourcepoint.cmplibrary.SpConsentLib
15-
import com.sourcepoint.cmplibrary.core.nativemessage.MessageStructure
1611
import com.sourcepoint.cmplibrary.creation.ConfigOption.SUPPORT_LEGACY_USPSTRING
1712
import com.sourcepoint.cmplibrary.creation.SpConfigDataBuilder
1813
import com.sourcepoint.cmplibrary.creation.makeConsentLib
@@ -23,22 +18,21 @@ import com.sourcepoint.cmplibrary.util.clearAllData
2318
import com.sourcepoint.cmplibrary.util.userConsents
2419
import com.sourcepoint.reactnativecmp.arguments.BuildOptions
2520
import com.sourcepoint.reactnativecmp.arguments.toList
26-
import com.sourcepoint.reactnativecmp.consents.RNSPUserData
2721
import com.sourcepoint.reactnativecmp.consents.RNSPGDPRConsent
28-
import org.json.JSONObject
22+
import com.sourcepoint.reactnativecmp.consents.RNSPUserData
23+
import kotlinx.serialization.encodeToString
24+
import kotlinx.serialization.json.Json
2925

3026
data class SPLoadMessageParams(val authId: String?) {
3127
constructor(fromReadableMap: ReadableMap?) : this(authId = fromReadableMap?.getString("authId"))
3228
}
3329

34-
@ReactModule(name = ReactNativeCmpModule.NAME)
3530
class ReactNativeCmpModule(reactContext: ReactApplicationContext) : NativeReactNativeCmpSpec(reactContext),
3631
SpClient {
3732
private var spConsentLib: SpConsentLib? = null
3833

3934
override fun getName() = NAME
4035

41-
@ReactMethod
4236
override fun build(
4337
accountId: Double,
4438
propertyId: Double,
@@ -74,7 +68,7 @@ class ReactNativeCmpModule(reactContext: ReactApplicationContext) : NativeReactN
7468
}.build()
7569

7670
reactApplicationContext.currentActivity?.let {
77-
spConsentLib = makeConsentLib(config, it, this)
71+
spConsentLib = makeConsentLib(config, it, this, parsedOptions.androidDismissMessageOnBackPress)
7872
} ?: run {
7973
onError(Error("No activity found when building the SDK"))
8074
}
@@ -84,7 +78,6 @@ class ReactNativeCmpModule(reactContext: ReactApplicationContext) : NativeReactN
8478
reactApplicationContext.runOnUiQueueThread(runnable)
8579
}
8680

87-
@ReactMethod
8881
override fun loadMessage(params: ReadableMap?) {
8982
val parsedParams = SPLoadMessageParams(fromReadableMap = params)
9083

@@ -93,22 +86,18 @@ class ReactNativeCmpModule(reactContext: ReactApplicationContext) : NativeReactN
9386
}
9487
}
9588

96-
@ReactMethod
9789
override fun clearLocalData() {
9890
clearAllData(reactApplicationContext)
9991
}
10092

101-
@ReactMethod
10293
override fun getUserData(promise: Promise) {
10394
promise.resolve(userConsentsToWriteableMap(userConsents(reactApplicationContext)))
10495
}
10596

106-
@ReactMethod
10797
override fun loadGDPRPrivacyManager(pmId: String) {
10898
runOnMainThread { spConsentLib?.loadPrivacyManager(pmId, GDPR) }
10999
}
110100

111-
@ReactMethod
112101
override fun loadUSNatPrivacyManager(pmId: String) {
113102
runOnMainThread { spConsentLib?.loadPrivacyManager(pmId, USNAT) }
114103
}
@@ -125,7 +114,12 @@ class ReactNativeCmpModule(reactContext: ReactApplicationContext) : NativeReactN
125114
runOnMainThread { spConsentLib?.dismissMessage() }
126115
}
127116

128-
override fun postCustomConsentGDPR(vendors: ReadableArray, categories: ReadableArray, legIntCategories: ReadableArray, callback: Callback) {
117+
override fun postCustomConsentGDPR(
118+
vendors: ReadableArray,
119+
categories: ReadableArray,
120+
legIntCategories: ReadableArray,
121+
callback: Callback
122+
) {
129123
runOnMainThread {
130124
spConsentLib?.customConsentGDPR(
131125
vendors.toList(),
@@ -142,7 +136,12 @@ class ReactNativeCmpModule(reactContext: ReactApplicationContext) : NativeReactN
142136
}
143137
}
144138

145-
override fun postDeleteCustomConsentGDPR(vendors: ReadableArray, categories: ReadableArray, legIntCategories: ReadableArray, callback: Callback) {
139+
override fun postDeleteCustomConsentGDPR(
140+
vendors: ReadableArray,
141+
categories: ReadableArray,
142+
legIntCategories: ReadableArray,
143+
callback: Callback
144+
) {
146145
runOnMainThread {
147146
spConsentLib?.deleteCustomConsentTo(
148147
vendors.toList(),
@@ -170,33 +169,29 @@ class ReactNativeCmpModule(reactContext: ReactApplicationContext) : NativeReactN
170169
}
171170

172171
override fun onAction(view: View, consentAction: ConsentAction): ConsentAction {
173-
emitOnAction(createMap().apply {
174-
putString("actionType", RNSourcepointActionType.from(consentAction.actionType).name)
175-
putString("customActionId", consentAction.customActionId)
176-
})
172+
emitInternalOnAction(Json.encodeToString(mapOf(
173+
"actionType" to RNSourcepointActionType.from(consentAction.actionType).name,
174+
"customActionId" to consentAction.customActionId
175+
)))
177176
return consentAction
178177
}
179178

180179
override fun onConsentReady(consent: SPConsents) {}
181180

182181
override fun onError(error: Throwable) {
183-
emitOnError(createMap().apply { putString("description", error.message) })
182+
emitInternalOnError(Json.encodeToString(mapOf("description" to error.message)))
184183
}
185184

186-
@Deprecated("onMessageReady callback will be removed in favor of onUIReady. Currently this callback is disabled.")
187-
override fun onMessageReady(message: JSONObject) {}
188-
189-
override fun onNativeMessageReady(
190-
message: MessageStructure,
191-
messageController: NativeMessageController
192-
) {}
193-
194185
override fun onNoIntentActivitiesFound(url: String) {}
195186

196187
override fun onSpFinished(sPConsents: SPConsents) {
197188
emitOnFinished()
198189
}
199190

191+
override fun onMessageInactivityTimeout() {
192+
emitOnMessageInactivityTimeout()
193+
}
194+
200195
override fun onUIFinished(view: View) {
201196
spConsentLib?.removeView(view)
202197
emitOnSPUIFinished()

android/src/main/java/com/sourcepoint/reactnativecmp/arguments/Arguments.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,13 @@ fun ReadableMap.getDoubleOrNull(name: String) =
168168
null
169169
}
170170

171+
fun ReadableMap.getBooleanOrNull(name: String) =
172+
if (hasKey(name) && !isNull(name)) {
173+
getBoolean(name)
174+
} else {
175+
null
176+
}
177+
171178
inline fun <reified T> ReadableArray.toList(): List<T> = List(size()) {
172179
when (T::class) {
173180
String::class -> getString(it)

android/src/main/java/com/sourcepoint/reactnativecmp/arguments/BuildOptions.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@ import com.sourcepoint.cmplibrary.model.MessageLanguage.ENGLISH
77
data class BuildOptions(
88
val language: MessageLanguage,
99
val messageTimeoutInSeconds: Long,
10+
val androidDismissMessageOnBackPress: Boolean
1011
) {
1112
val messageTimeoutInMilliseconds = messageTimeoutInSeconds * 1000L
1213

1314
constructor(options: ReadableMap?) : this(
1415
language = MessageLanguage.entries.find { it.value == options?.getString("language") } ?: ENGLISH,
15-
messageTimeoutInSeconds = options?.getDoubleOrNull("messageTimeoutInSeconds")?.toLong() ?: 30L
16+
messageTimeoutInSeconds = options?.getDoubleOrNull("messageTimeoutInSeconds")?.toLong() ?: 30L,
17+
androidDismissMessageOnBackPress = options?.getBooleanOrNull("androidDismissMessageOnBackPress") ?: true
1618
)
1719
}

example/android/app/build.gradle

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,6 @@ android {
108108
proguardFile "${rootProject.projectDir}/../node_modules/detox/android/detox/proguard-rules-app.pro"
109109
}
110110
}
111-
compileOptions {
112-
coreLibraryDesugaringEnabled = true
113-
}
114111
}
115112

116113
dependencies {
@@ -119,7 +116,6 @@ dependencies {
119116
androidTestImplementation "androidx.test:core:1.6.1"
120117
androidTestImplementation('com.wix:detox:+')
121118
implementation 'androidx.appcompat:appcompat:1.7.1'
122-
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.5")
123119

124120
if (hermesEnabled.toBoolean()) {
125121
implementation("com.facebook.react:hermes-android")

example/ios/Podfile.lock

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
PODS:
22
- boost (1.84.0)
3-
- ConsentViewController (7.11.1):
3+
- ConsentViewController (7.12.1):
44
- Down (~> 0.11.0)
55
- SPMobileCore (= 0.1.11)
66
- DoubleConversion (1.1.6)
@@ -1659,8 +1659,8 @@ PODS:
16591659
- React-logger (= 0.79.2)
16601660
- React-perflogger (= 0.79.2)
16611661
- React-utils (= 0.79.2)
1662-
- ReactNativeCmp (1.0.4):
1663-
- ConsentViewController (= 7.11.1)
1662+
- ReactNativeCmp (1.0.9-beta.2):
1663+
- ConsentViewController (= 7.12.1)
16641664
- DoubleConversion
16651665
- glog
16661666
- hermes-engine
@@ -1919,7 +1919,7 @@ EXTERNAL SOURCES:
19191919

19201920
SPEC CHECKSUMS:
19211921
boost: 7e761d76ca2ce687f7cc98e698152abd03a18f90
1922-
ConsentViewController: 6cd17ebf78b80e7d32bf3d6b0b46d20a40e8cad9
1922+
ConsentViewController: 653e30da12ad26fbe47b8adfd0ca545c69c10d0e
19231923
DoubleConversion: cb417026b2400c8f53ae97020b2be961b59470cb
19241924
fast_float: 06eeec4fe712a76acc9376682e4808b05ce978b6
19251925
FBLazyVector: 84b955f7b4da8b895faf5946f73748267347c975
@@ -1989,11 +1989,11 @@ SPEC CHECKSUMS:
19891989
ReactAppDependencyProvider: 04d5eb15eb46be6720e17a4a7fa92940a776e584
19901990
ReactCodegen: c63eda03ba1d94353fb97b031fc84f75a0d125ba
19911991
ReactCommon: 76d2dc87136d0a667678668b86f0fca0c16fdeb0
1992-
ReactNativeCmp: 8502676551832d19d227fa2b161b4c7354cd686c
1992+
ReactNativeCmp: d79d97ff49c3e5ca3aa5f8a6608dbe06a30e7c7a
19931993
SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748
19941994
SPMobileCore: 220d109e404cb17169f7e26f2a34c6022b80079a
19951995
Yoga: c758bfb934100bb4bf9cbaccb52557cee35e8bdf
19961996

19971997
PODFILE CHECKSUM: decdc7519d77aa5eae65b167fa59bcfce25e15d2
19981998

1999-
COCOAPODS: 1.15.2
1999+
COCOAPODS: 1.16.2

example/src/App.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ const config = {
3838
// is disabled in the Sourcepoint dashboard
3939
language: SPMessageLanguage.ENGLISH,
4040
messageTimeoutInSeconds: 20,
41+
// Allows Android users to dismiss the consent message on back press.
42+
// True by default.
43+
// Set it to false if you wish to prevent this users from dismissing the message on back press.
44+
androidDismissMessageOnBackPress: false,
4145
},
4246
gdprPMId: '488393',
4347
usnatPMId: '988851',
@@ -89,6 +93,10 @@ export default function App() {
8993
console.log(`action: ${actionType}`)
9094
);
9195

96+
consentManager.current?.onMessageInactivityTimeout(() => {
97+
console.log("User inactive");
98+
});
99+
92100
consentManager.current?.onError((description) => {
93101
setSDKStatus(SDKStatus.Errored);
94102
console.error(description);

ios/RNSourcepointCmp.swift

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,26 @@ import React
2828
self.customActionId = customActionId
2929
}
3030

31-
@objc public func toDictionary() -> [String: Any] {
31+
func toDictionary() -> [String: Any] {
3232
["actionType": type.description, "customActionId": customActionId]
3333
}
34+
35+
@objc public func stringifiedJson() -> String {
36+
if let jsonData = try? JSONSerialization.data(withJSONObject: toDictionary()),
37+
let jsonString = String(data: jsonData, encoding: .utf8) {
38+
return jsonString
39+
} else {
40+
return "{\"actionType\":\"unknown\"}"
41+
}
42+
}
3443
}
3544

3645
@objc public protocol ReactNativeCmpImplDelegate {
3746
func onAction(_ action: RNAction)
3847
func onSPUIReady()
3948
func onSPUIFinished()
4049
func onFinished()
50+
func onMessageInactivityTimeout()
4151
func onError(description: String)
4252
}
4353

@@ -147,6 +157,10 @@ import React
147157
delegate?.onFinished()
148158
}
149159

160+
public func onMessageInactivityTimeout() {
161+
delegate?.onMessageInactivityTimeout()
162+
}
163+
150164
public func onError(error: SPError) {
151165
print("Something went wrong", error)
152166
delegate?.onError(description: error.description)
@@ -180,6 +194,10 @@ private class CMPDelegateHandler: NSObject, SPDelegate {
180194
parent?.onSPFinished(userData: userData)
181195
}
182196

197+
func onMessageInactivityTimeout() {
198+
parent?.onMessageInactivityTimeout()
199+
}
200+
183201
func onError(error: SPError) {
184202
parent?.onError(error: error)
185203
}

0 commit comments

Comments
 (0)