1 | # appconsent-clear-reactnative
|
2 |
|
3 | [![npm version](https://img.shields.io/npm/v/appconsent-clear-reactnative)](https://www.npmjs.com/package/appconsent-clear-reactnative)
|
4 | [![license](https://badgen.net/npm/license/appconsent-clear-reactnative)](https://gitlab.datalf.chat/sfbx/dev/appconsent/cmp/mobile/react-native/appconsent-clear-reactnative/-/blob/master/LICENSE)
|
5 | [![types](https://badgen.net/npm/types/appconsent-clear-reactnative)](https://www.npmjs.com/~types)
|
6 | [![install size](https://packagephobia.com/badge?p=appconsent-clear-reactnative)](https://packagephobia.com/result?p=appconsent-clear-reactnative)
|
7 | [![minizipped size](https://badgen.net/bundlephobia/minzip/appconsent-clear-reactnative)](https://bundlephobia.com/package/appconsent-clear-reactnative)
|
8 | [![downloads monthly](https://img.shields.io/npm/dm/appconsent-clear-reactnative)](https://www.npmtrends.com/appconsent-clear-reactnative)
|
9 | [![downloads total](https://img.shields.io/npm/dt/appconsent-clear-reactnative)](https://www.npmtrends.com/appconsent-clear-reactnative)
|
10 |
|
11 | <img src="https://sfbx.io/wp-content/uploads/2021/02/Logo-SFBX-Privacy-Matters-2.png" alt="SFBX" style="zoom:1%;float: left;" height="72" />
|
12 |
|
13 | AppConsent® cmp, the transparency-based consent management platform.
|
14 |
|
15 | The design displayed by the CMP can be configured from: https://app.appconsent.io/.<br />
|
16 | The display below is the default graphic configuration.
|
17 | <br /><br />
|
18 | ## Visual example
|
19 |
|
20 | You can see some screens (not exhaustive):
|
21 | * Introduction screen
|
22 | * Configuration screen (for more detailed user input)
|
23 | * Explanation / consent category entry screen
|
24 | * The screen that lists your vendors and allows manual entry of each of them
|
25 | * Congratulation screen (can be disabled)
|
26 |
|
27 | <div>
|
28 |
|
29 | <img src="https://docs.sfbx.io/img/react-native/demo_android.gif" alt="Demo Android Version"/>
|
30 |
|
31 | <img src="https://docs.sfbx.io/img/react-native/demo_ios.gif" alt="Demo iOS Version"/>
|
32 | <br />
|
33 | <br />
|
34 | <br />
|
35 | </div>
|
36 |
|
37 | ## Getting started
|
38 |
|
39 | Setup the environment for react-native as explained [here.](https://reactnative.dev/docs/environment-setup "Setting up the development environment")
|
40 |
|
41 | ```sh
|
42 | npm install appconsent-clear-reactnative --save
|
43 | ```
|
44 |
|
45 | ### iOS
|
46 |
|
47 | Run `pod install`.
|
48 |
|
49 | > :memo: AppConsent SDK supports the new `App Tracking Transparency` framework (> iOS 14+ available). You must register the `NSUserTrackingUsageDescription` key in the `Info.plist` file of your application.
|
50 |
|
51 | The documentation for the iOS AppConsent framework can be found [here](https://docs.sfbx.io/configuration/notice-implementation/ios "SFBX iOS Documentation").
|
52 |
|
53 | ### Android
|
54 |
|
55 | In `project/build.gradle`, add this maven url in the allprojects/repositories block.
|
56 | ```
|
57 | allprojects {
|
58 | repositories {
|
59 | maven {
|
60 | url "https://artifactory.datalf.chat/artifactory/app-consent-v2-release"
|
61 | }
|
62 | }
|
63 | }
|
64 | ```
|
65 |
|
66 | The Documentation for the Android AppConsent framework can be found [here](https://docs.sfbx.io/configuration/notice-implementation/android "SFBX Android Documentation").
|
67 |
|
68 | ## Usage
|
69 |
|
70 | ### Instantiate
|
71 |
|
72 | ```javascript
|
73 | /*
|
74 | * It's important to wait for the method to initialize.
|
75 | * On iOS, instantiation is almost instantaneous (3ms)*;
|
76 | * But on Android initialization takes longer (up to 23ms)*;
|
77 | *
|
78 | * This is mainly due to initialization of the WebView component
|
79 | * and GAID retrieval by Google services.
|
80 | *
|
81 | * '*' Depending on the performance of your devices
|
82 | */
|
83 |
|
84 | import AppConsent from 'appconsent-clear-reactnative';
|
85 |
|
86 | // Configure at launch (appKey:forceApplyGDPR:forceATT)
|
87 | await AppConsent.configureWith("appKey", true, true);
|
88 | ```
|
89 |
|
90 | ### Simple use case
|
91 |
|
92 | Display of CMP after initialization
|
93 |
|
94 | ```javascript
|
95 | import * as React from 'react';
|
96 | import { Component } from 'react';
|
97 | import { Button, Platform, StyleSheet, View, Text } from 'react-native';
|
98 | import AppConsent from 'appconsent-clear-reactnative';
|
99 |
|
100 | async function initAppConsent() {
|
101 | // To force CMP to be displayed regardless of your users' region
|
102 | // Use *true* instead of *false*.
|
103 | await AppConsent.configureWith(
|
104 | 'appKey',
|
105 | false,
|
106 | true
|
107 | );
|
108 | }
|
109 |
|
110 | export default class App extends Component<{}> {
|
111 |
|
112 | componentDidMount() {
|
113 | // Configure
|
114 | initAppConsent().then(() => {
|
115 | console.log("initAppConsent finished")
|
116 |
|
117 | AppConsent.checkForUpdate()
|
118 | .then((success: boolean) => {
|
119 | console.log('🔥 checkForUpdate => ' + success);
|
120 | // A positive checkForUpdate means that you have to reintroduce the CMP to your users
|
121 | // as their consent is not synchronous with your (new) Notice configuration.
|
122 | if (success === true) {
|
123 | // if an update is necessary (and even if it isn't)
|
124 | // you can delete your users' consent locally from their device.
|
125 | AppConsent.clearConsent();
|
126 | // Then present the CMP again
|
127 | AppConsent.present(false);
|
128 | }
|
129 | })
|
130 | .catch((err: any) => console.log(err));
|
131 | }
|
132 | ).catch((_: any) =>
|
133 | console.log("error happened during initAppConsent")
|
134 | )
|
135 | }
|
136 |
|
137 | render() {
|
138 | return (
|
139 | <Text>Hello World</Text>
|
140 | );
|
141 | }
|
142 | }
|
143 |
|
144 | const styles = StyleSheet.create({
|
145 | ...
|
146 | });
|
147 | ```
|
148 |
|
149 | ### Dev sample - Full sample
|
150 |
|
151 | This example provides you with a test screen.<br /><br />
|
152 | It allowing you to initialize the CMP, display it when the application is launched<br />
|
153 | (<b>forceApplyGDPR</b> has been forced to true) and test various options using the buttons<br />
|
154 | like delete user consent, define/read/save externalIds, force display of the configuration screen.
|
155 |
|
156 | Modify this example to test other methods
|
157 |
|
158 | ```javascript
|
159 | import * as React from 'react';
|
160 | import { Component } from 'react';
|
161 | import { Button, Platform, StyleSheet, View, Text } from 'react-native';
|
162 | import AppConsent from 'appconsent-clear-reactnative';
|
163 |
|
164 | async function initAppConsent() {
|
165 | console.log('>> initAppConsent');
|
166 | console.log(':: initAppConsent >> configureWith');
|
167 | await AppConsent.configureWith(
|
168 | 'appKey',
|
169 | true, // forceApplyGDPR to be sure that the CMP will display whatever the users' region
|
170 | true
|
171 | );
|
172 | console.log(':: initAppConsent << configureWith');
|
173 | console.log('<< initAppConsent');
|
174 | }
|
175 |
|
176 | async function defineCustomExternalIds(){
|
177 | // You may find it useful to save some information related to your functional domain.
|
178 | try {
|
179 | // Defined certain arbitrary functional values
|
180 | const isExternalIdsSet = await AppConsent.setExternalIds({
|
181 | user_premium_id: 'AdhsI7hdk',
|
182 | another_key: 'another_value',
|
183 | });
|
184 | console.log('setExternalIds result: ' + isExternalIdsSet);
|
185 | } catch (error) {
|
186 | console.warn('Error while setting external ids', error);
|
187 | }
|
188 | }
|
189 |
|
190 | async function checkConsentAlreadyGiven(){
|
191 | try {
|
192 | // Check if user has already given his consent
|
193 | // just to check
|
194 | const consentAlreadyGiven = await AppConsent.consentAlreadyGiven();
|
195 |
|
196 | if (consentAlreadyGiven === true) {
|
197 | console.log('consentAlreadyGiven: ' + consentAlreadyGiven);
|
198 | } else {
|
199 | console.log('user consent did not given');
|
200 | }
|
201 | } catch (error) {
|
202 | console.warn('Error while determining consent status', error);
|
203 | }
|
204 | }
|
205 |
|
206 | async function initCmp() {
|
207 | await initAppConsent();
|
208 | console.log('🎉 AppConsent fully initialized');
|
209 |
|
210 | // Use the SDK to process/check/compare/etc. as you need and once ready
|
211 | // check whether an update of your leaflet has been made and display the CMP to your users or not.
|
212 | await defineCustomExternalIds();
|
213 | await checkConsentAlreadyGiven();
|
214 | }
|
215 |
|
216 | export default class App extends Component<{}> {
|
217 | state = {
|
218 | status: 'starting',
|
219 | message: '--',
|
220 | };
|
221 |
|
222 | componentDidMount() {
|
223 | // Configure
|
224 | initCmp()
|
225 | .then(() => {
|
226 | console.log('initCmp finished');
|
227 |
|
228 | // Check For Update
|
229 | AppConsent.checkForUpdate()
|
230 | .then((success: boolean) => {
|
231 | console.log('🔥 checkForUpdate => ' + success);
|
232 | // A positive checkForUpdate means that you have to reintroduce the CMP to your users
|
233 | // as their consent is not synchronous with your (new) Notice configuration.
|
234 | if (success === true) {
|
235 | // if an update is necessary (and even if it isn't)
|
236 | // you can delete your users' consent locally from their device.
|
237 | AppConsent.clearConsent();
|
238 | // Then present the CMP again
|
239 | AppConsent.present(false);
|
240 | }
|
241 | })
|
242 | .catch((err: any) => console.log(err));
|
243 |
|
244 | // Is GDPR Country
|
245 | AppConsent.isGDPRCountry()
|
246 | .then((success: boolean) =>
|
247 | console.log('🔥 isGDPRCountry => ' + success)
|
248 | )
|
249 | .catch((err: any) => console.log(err));
|
250 |
|
251 | // Consent Already Given
|
252 | AppConsent.consentAlreadyGiven()
|
253 | .then((success: boolean) =>
|
254 | console.log('🔥 consentAlreadyGiven => ' + success)
|
255 | )
|
256 | .catch((err: any) => console.log(err));
|
257 |
|
258 | // Consentable Allowed by extraId
|
259 | AppConsent.extraConsentableAllowed('1')
|
260 | .then((success: boolean) =>
|
261 | console.log('🔥 extraConsentableAllowed => ' + success)
|
262 | )
|
263 | .catch((err: any) => console.log(err));
|
264 |
|
265 | // Vendor Allowed by extraId
|
266 | AppConsent.extraVendorAllowed('1')
|
267 | .then((success: boolean) =>
|
268 | console.log('🔥 extraVendorAllowed => ' + success)
|
269 | )
|
270 | .catch((err: any) => console.log(err));
|
271 |
|
272 | // Extra Floating Purpose Allowed
|
273 | AppConsent.extraFloatingPurposeAllowed('NkDawTu1')
|
274 | .then((success: boolean) =>
|
275 | console.log('🔥 extraFloatingPurposeAllowed => ' + success)
|
276 | )
|
277 | .catch((err: any) => console.log(err));
|
278 |
|
279 | // Set Consentable Consent
|
280 | AppConsent.setConsentableConsent({ '1': 1 })
|
281 | .then((success: boolean) =>
|
282 | console.log('🔥 setConsentableConsent => ' + success)
|
283 | )
|
284 | .catch((err: any) => console.log(err));
|
285 |
|
286 | // Set Extra Consentable Consent
|
287 | AppConsent.setExtraConsentableConsent({ TDWLFix3: 1 })
|
288 | .then((success: boolean) =>
|
289 | console.log('🔥 setExtraConsentableConsent => ' + success)
|
290 | )
|
291 | .catch((err: any) => console.log(err));
|
292 |
|
293 | //iOS ONLY
|
294 |
|
295 | // Get forceATT IOS
|
296 | Platform.OS === 'ios' &&
|
297 | AppConsent.getForceATT()
|
298 | .then((success: boolean) =>
|
299 | console.log('🔥 getForceATT => ' + success)
|
300 | )
|
301 | .catch((err: any) => console.log(err));
|
302 |
|
303 | // App Tracking is available
|
304 | Platform.OS === 'ios' &&
|
305 | AppConsent.appTrackingIsAvailable()
|
306 | .then((success: boolean) =>
|
307 | console.log('🔥 appTrackingIsAvailable => ' + success)
|
308 | )
|
309 | .catch((err: any) => console.log(err));
|
310 |
|
311 | // App Tracking Authorization Given
|
312 | Platform.OS === 'ios' &&
|
313 | AppConsent.appTrackingAuthorizationGiven()
|
314 | .then((success: number) =>
|
315 | console.log('🔥 appTrackingAuthorizationGiven => ' + success)
|
316 | )
|
317 | .catch((err: any) => console.log(err));
|
318 |
|
319 | // App Tracking Authorization Status
|
320 | Platform.OS === 'ios' &&
|
321 | AppConsent.appTrackingAuthorizationStatus()
|
322 | .then((success: number) =>
|
323 | console.log('🔥 appTrackingAuthorizationStatus => ' + success)
|
324 | )
|
325 | .catch((err: any) => console.log(err));
|
326 | })
|
327 | .catch((_: any) => console.log('error happened during initCmp'));
|
328 | }
|
329 |
|
330 | render() {
|
331 | return (
|
332 | <View style={styles.container}>
|
333 | <Text style={styles.titleLabel}>App Consent</Text>
|
334 | <View>
|
335 | <Button
|
336 | title="Present: true"
|
337 | onPress={() => AppConsent.present(true)}
|
338 | />
|
339 | </View>
|
340 | <View>
|
341 | <Button
|
342 | title="Present: false"
|
343 | onPress={() => AppConsent.present(false)}
|
344 | />
|
345 | </View>
|
346 | <View>
|
347 | <Button
|
348 | title="Clear Consent"
|
349 | onPress={() => AppConsent.clearConsent()}
|
350 | />
|
351 | </View>
|
352 | <View>
|
353 | <Button
|
354 | title="Get External Ids"
|
355 | onPress={() =>
|
356 | AppConsent.getExternalIds()
|
357 | .then((success: string) => {
|
358 | console.log('🔥 getExternalIds => ' + success);
|
359 | })
|
360 | .catch((err: any) => console.log(err))
|
361 | }
|
362 | />
|
363 | </View>
|
364 | <View>
|
365 | <Button
|
366 | title="Set External Ids"
|
367 | onPress={() => {
|
368 | AppConsent.setExternalIds({
|
369 | zanzan: 'abso',
|
370 | hello: 'world',
|
371 | kara: 'monga',
|
372 | anila: 'zora',
|
373 | })
|
374 | .then((success: boolean) =>
|
375 | console.log('🔥 setExternalIds => ' + success)
|
376 | )
|
377 | .catch((err: any) => console.log(err));
|
378 | }}
|
379 | />
|
380 | </View>
|
381 | <View>
|
382 | <Button
|
383 | title="Save External Ids"
|
384 | onPress={() =>
|
385 | AppConsent.saveExternalIds()
|
386 | .then((success: boolean) =>
|
387 | console.log('🔥 Save External Ids => ' + success)
|
388 | )
|
389 | .catch((err: any) =>
|
390 | console.log('🔥 Save External Ids ERROR => ' + err)
|
391 | )
|
392 | }
|
393 | />
|
394 | </View>
|
395 | </View>
|
396 | );
|
397 | }
|
398 | }
|
399 |
|
400 | const styles = StyleSheet.create({
|
401 | container: {
|
402 | flex: 1,
|
403 | justifyContent: 'center',
|
404 | alignItems: 'center',
|
405 | backgroundColor: '#F5FCFF',
|
406 | },
|
407 | welcome: {
|
408 | fontSize: 20,
|
409 | textAlign: 'center',
|
410 | margin: 10,
|
411 | },
|
412 | instructions: {
|
413 | textAlign: 'center',
|
414 | color: '#333333',
|
415 | marginBottom: 5,
|
416 | },
|
417 | titleLabel: {
|
418 | fontSize: 30,
|
419 | fontWeight: 'bold',
|
420 | marginBottom: 100,
|
421 | },
|
422 | versionLabel: {
|
423 | marginTop: 100,
|
424 | fontSize: 20,
|
425 | },
|
426 | });
|
427 | ```
|
428 |
|
429 | ## Documentation
|
430 |
|
431 | Our general documentation is accessible at [https://docs.sfbx.io](https://docs.sfbx.io).
|
432 |
|
433 | This module's API documentation is accessible at [https://docs.sfbx.io/react-api-reference/](https://docs.sfbx.io/react-api-reference/).
|
434 |
|
435 | ## License
|
436 |
|
437 | MIT
|