@cookieinformation/react-native-sdk 0.5.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 CookieInformation
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,353 @@
1
+ # Cookie Information React Native SDK
2
+
3
+ React Native wrapper for the Cookie Information Mobile Consents SDKs.
4
+
5
+ Native SDKs:
6
+ - Android: https://github.com/cookie-information/android-release
7
+ - iOS: https://github.com/cookie-information/ios-release
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ npm install @cookieinformation/react-native-sdk
13
+ # or
14
+ yarn add @cookieinformation/react-native-sdk
15
+ ```
16
+
17
+ # Using the SDK
18
+
19
+ ## Initializing
20
+
21
+ Initialize the SDK before calling any other method. You can initialize with or without UI customization.
22
+ SDK credentials can be fetched from the Cookie Information platform: https://go.cookieinformation.com/login
23
+
24
+ The SDK uses the `languageCode` you pass during initialization for all UI components and ignores the system language. If `languageCode` is not set, the SDK uses the device locale. You must ensure the selected language is configured in the Cookie Information platform and that content is provided for that language.
25
+
26
+ Recommended flow: initialize once, then call `showPrivacyPopUpIfNeeded` when needed (typically on app start).
27
+
28
+ Minimum required data for initialization:
29
+ - `clientId`
30
+ - `clientSecret`
31
+ - `solutionId`
32
+
33
+ ```ts
34
+ import MobileConsent from '@cookieinformation/react-native-sdk';
35
+
36
+ await MobileConsent.initialize({
37
+ clientId: 'YOUR_CLIENT_ID',
38
+ clientSecret: 'YOUR_CLIENT_SECRET',
39
+ solutionId: 'YOUR_SOLUTION_ID',
40
+ });
41
+ ```
42
+
43
+ Here is an example of all the arguments and data that support the SDK:
44
+
45
+ ```ts
46
+ await MobileConsent.initialize({
47
+ clientId: 'YOUR_CLIENT_ID',
48
+ clientSecret: 'YOUR_CLIENT_SECRET',
49
+ solutionId: 'YOUR_SOLUTION_ID',
50
+ languageCode: 'EN', // optional
51
+ enableNetworkLogger: false, // iOS only
52
+ ui: {
53
+ ios: {
54
+ accentColor: '#2E5BFF',
55
+ fontSet: {
56
+ largeTitle: { size: 34, weight: 'bold' },
57
+ body: { size: 14, weight: 'regular' },
58
+ bold: { size: 14, weight: 'bold' },
59
+ },
60
+ },
61
+ android: {
62
+ lightColorScheme: {
63
+ primary: '#FF0000',
64
+ secondary: '#FFFF00',
65
+ tertiary: '#FFC0CB',
66
+ },
67
+ darkColorScheme: {
68
+ primary: '#00FF00',
69
+ secondary: '#008000',
70
+ tertiary: '#000000',
71
+ },
72
+ typography: {
73
+ bodyMedium: { font: 'inter_regular', size: 14 },
74
+ },
75
+ },
76
+ },
77
+ });
78
+ ```
79
+
80
+ Notes:
81
+ - Android `font` is a resource name under `android/app/src/main/res/font`.
82
+ - Colors accept `#RRGGBB` or `#AARRGGBB`.
83
+ - iOS uses system fonts if `name` is omitted.
84
+
85
+ ## Using built-in mobile consents UI
86
+
87
+ SDK contains built-in screens for managing consents. Please ensure you set the correct language code you expect the consents to use, and that it has been fully configured in the Cookie Information platform.
88
+
89
+ | iOS | Android |
90
+ | --- | --- |
91
+ | ![iOS screenshot](docs/screenshots/ios.png) | ![Android screenshot](docs/screenshots/android.png) |
92
+
93
+ ## Privacy Pop-Up
94
+
95
+ ### Standard flows
96
+
97
+ #### Presenting the privacy pop-up
98
+
99
+ To show the Privacy Pop Up screen regardless of state, use `showPrivacyPopUp` (typically used in settings to allow modification of consent). To show the Privacy Pop Up screen only when the user has not consented to the latest version, use `showPrivacyPopUpIfNeeded` (typically used at startup to present the privacy screen conditionally; see more below).
100
+
101
+ ```ts
102
+ showPrivacyPopUp(): Promise<TrackingConsents>
103
+ ```
104
+
105
+ ```ts
106
+ const consents = await MobileConsent.showPrivacyPopUp();
107
+
108
+ // Return type: TrackingConsents (Record<string, boolean | undefined>)
109
+ // TrackingConsents is a map of consent choices keyed by purpose/category:
110
+ // - keys: necessary, functional, statistical, marketing, custom (plus any custom keys)
111
+ // - values: boolean (true/false) or undefined
112
+ // Example return shape:
113
+ // {
114
+ // necessary: true,
115
+ // functional: false,
116
+ // statistical: true,
117
+ // marketing: false,
118
+ // custom: true
119
+ // }
120
+
121
+ if (consents.marketing) {
122
+ // enable marketing SDKs
123
+ } else {
124
+ // disable marketing SDKs
125
+ }
126
+ ```
127
+
128
+ The above function resolves with the user’s selections (a key/value map of consent categories to booleans). Use this result to enable or disable third‑party SDKs based on consent.
129
+
130
+ ### Presenting the privacy pop-up conditionally
131
+
132
+ `showPrivacyPopUpIfNeeded` is typically used to present the popup after app start (or at a point you choose). The method checks if a valid consent is already saved locally on the device and also checks if there are any updates on the Cookie Information server. If there is no consent saved or the consent version is different from the one available on the server, the popup is presented; otherwise it resolves immediately with the current consent data. Use `ignoreVersionChanges` to ignore consent version changes coming from the server (iOS only).
133
+
134
+ ```ts
135
+ showPrivacyPopUpIfNeeded(
136
+ options?: { ignoreVersionChanges?: boolean; userId?: string | null }
137
+ ): Promise<TrackingConsents>
138
+ ```
139
+
140
+ ```ts
141
+ const consents = await MobileConsent.showPrivacyPopUpIfNeeded();
142
+
143
+ // Use the result to enable/disable SDKs
144
+ if (consents.marketing) {
145
+ // enable marketing SDKs
146
+ } else {
147
+ // disable marketing SDKs
148
+ }
149
+ ```
150
+
151
+ With options (Android `userId`, iOS `ignoreVersionChanges`):
152
+
153
+ ```ts
154
+ const consents = await MobileConsent.showPrivacyPopUpIfNeeded({
155
+ ignoreVersionChanges: true, // iOS only
156
+ userId: 'user_123', // optional on Android
157
+ });
158
+
159
+ // Example: read custom keys or localized titles
160
+ if (consents['Age Consent']) {
161
+ // handle custom consent item
162
+ }
163
+ ```
164
+
165
+ ### Handling errors
166
+
167
+ Both `showPrivacyPopUp` and `showPrivacyPopUpIfNeeded` reject on error. If an error happens, the selection is still persisted locally and an attempt is made the next time `showPrivacyPopUpIfNeeded` or `synchronizeIfNeeded` is called.
168
+
169
+ ```ts
170
+ try {
171
+ await MobileConsent.showPrivacyPopUpIfNeeded();
172
+ } catch (e) {
173
+ console.warn('Consent UI failed, retry later:', e);
174
+ // You can call showPrivacyPopUpIfNeeded() again later (e.g. next app start).
175
+ }
176
+ ```
177
+
178
+ ## Custom view
179
+
180
+ If the default consent UI does not fit your product, you can build your own custom view. Use the methods below to fetch the consent solution and submit the user’s choices.
181
+
182
+ All methods return Promises and must be called after `initialize()`.
183
+
184
+ ### initialize
185
+ Initialize the native SDKs before calling any other method.
186
+
187
+ ```ts
188
+ initialize(options: InitializeOptions): Promise<void>
189
+ ```
190
+
191
+ ### cacheConsentSolution
192
+
193
+ Fetches the latest consent solution from the server. On iOS, it also returns `consentSolutionVersionId` which you must pass to `saveConsents` when sending consents manually. Use the returned `consentItems` to build your own UI if needed.
194
+
195
+ ```ts
196
+ cacheConsentSolution(): Promise<{ consentItems: ConsentItem[]; consentSolutionVersionId?: string }>
197
+ ```
198
+
199
+ ```ts
200
+ const { consentItems, consentSolutionVersionId } =
201
+ await MobileConsent.cacheConsentSolution();
202
+
203
+ // Example usage: build your own UI from consentItems
204
+ const itemsForUi = consentItems.map((item) => ({
205
+ id: item.id,
206
+ title: item.title,
207
+ required: item.required,
208
+ accepted: item.accepted,
209
+ }));
210
+ ```
211
+
212
+ ### saveConsents
213
+
214
+ Submits the selected consent items to the server and stores them locally. On iOS, you must pass `consentSolutionVersionId` from `cacheConsentSolution` (or a known version). On Android, `consentSolutionVersionId` is ignored.
215
+
216
+ Parameters:
217
+ - `consentItems`: List of consent items to save.
218
+ - `customData`: Optional custom data (e.g. email, device_id).
219
+ - `userId`: Android only, optional user id; omit or pass `null` for anonymous user. Ignored on iOS.
220
+ - `consentSolutionVersionId`: iOS only, optional version id override when already known.
221
+
222
+ ```ts
223
+ saveConsents(
224
+ consentItems: ConsentItem[],
225
+ customData?: Record<string, string> | null,
226
+ userId?: string | null,
227
+ consentSolutionVersionId?: string | null
228
+ ): Promise<SaveConsentsResponse>
229
+ ```
230
+
231
+ ```ts
232
+ const { consentItems, consentSolutionVersionId } =
233
+ await MobileConsent.cacheConsentSolution();
234
+
235
+ await MobileConsent.saveConsents(
236
+ consentItems,
237
+ { device_id: 'example-device' },
238
+ 'user_123', // optional userId on Android
239
+ consentSolutionVersionId
240
+ );
241
+ ```
242
+
243
+ Notes:
244
+ - On iOS, `consentSolutionVersionId` is required and can be obtained from `cacheConsentSolution()` or passed explicitly.
245
+ - On Android, `consentSolutionVersionId` is ignored.
246
+ - `userId` is optional on Android; pass `null` or omit for anonymous user.
247
+
248
+ ### getSavedConsents
249
+
250
+ `getSavedConsents` returns consent items stored on the device.
251
+ - Android: Returns items from the local DB (cached solution + user choices). Items may exist after `cacheConsentSolution` even before the user selects anything.
252
+ - iOS: Returns only consents that were saved when the user submitted choices (e.g. via the consent dialog or `saveConsents`). Empty until the user completes the flow at least once.
253
+
254
+ Parameters:
255
+ - `userId`: Android only, optional user id; omit or pass `null` for anonymous user. Ignored on iOS.
256
+
257
+ ```ts
258
+ getSavedConsents(userId?: string | null): Promise<{ consentItems: ConsentItem[] }>
259
+ ```
260
+
261
+ ```ts
262
+ const { consentItems } = await MobileConsent.getSavedConsents();
263
+ // Return type: { consentItems: ConsentItem[] }
264
+ ```
265
+
266
+ ### acceptAllConsents
267
+ Fetches the solution and saves “accept all” consents.
268
+
269
+ Parameters:
270
+ - `userId`: Android only, optional user id; omit or pass `null` for anonymous user. Ignored on iOS.
271
+
272
+ ```ts
273
+ acceptAllConsents(userId?: string | null): Promise<AcceptAllConsentsResponse>
274
+ ```
275
+
276
+ ### removeStoredConsents
277
+ Deletes stored consents on the device (does not delete server data).
278
+
279
+ Parameters:
280
+ - `userId`: Android only, optional user id; omit or pass `null` for anonymous user. Ignored on iOS.
281
+
282
+ ```ts
283
+ removeStoredConsents(userId?: string | null): Promise<void>
284
+ ```
285
+
286
+ ### synchronizeIfNeeded
287
+ Retries failed consent uploads.
288
+
289
+ ```ts
290
+ synchronizeIfNeeded(): Promise<void>
291
+ ```
292
+
293
+ ## Types (summary)
294
+
295
+ ```ts
296
+ type TrackingConsents = Record<string, boolean | undefined>;
297
+
298
+ interface ConsentItem {
299
+ id: number;
300
+ universalId: string;
301
+ title: string;
302
+ description: string;
303
+ required: boolean;
304
+ type: string;
305
+ accepted: boolean;
306
+ }
307
+
308
+ interface SaveConsentsResponse {
309
+ success: true;
310
+ savedCount: number;
311
+ }
312
+ ```
313
+
314
+ ## Logging
315
+
316
+ Enable network logging on iOS via `enableNetworkLogger: true` in `initialize()`.
317
+
318
+ ## Running the example app
319
+
320
+ The example app lives in `example/` and requires a native build (Expo Go is not supported).
321
+
322
+ ```bash
323
+ # from repo root
324
+ npm install
325
+ cd example
326
+ npm install
327
+
328
+ # generate native projects (first time or after native changes)
329
+ npx expo prebuild --clean
330
+
331
+ # run on device/simulator
332
+ npx expo run:ios
333
+ # or
334
+ npx expo run:android
335
+ ```
336
+
337
+ Notes:
338
+ - Update the credentials in `example/App.tsx` before running.
339
+
340
+ ## Notes
341
+
342
+ - Call `initialize()` before any other method.
343
+
344
+ ## Implementation
345
+
346
+ For additional customization options within MobileConsentsSDK, please contact our support team.
347
+
348
+ If something is missing or you want to change something, let us know.
349
+
350
+ ## Release automation
351
+
352
+ - GitHub Actions publish requires `NPM_TOKEN` repository secret.
353
+ - Release tags must match the `package.json` version (format `X.Y.Z`).
@@ -0,0 +1,67 @@
1
+ apply plugin: 'com.android.library'
2
+
3
+ group = 'expo.modules.mobileconsentssdk'
4
+ version = '0.1.0'
5
+
6
+ def nodeBinary = (findProperty("NODE_BINARY") ?: System.getenv("NODE_BINARY") ?: "node")
7
+
8
+ // Dynamic resolution for Expo modules core plugin (monorepo compatible)
9
+ def expoModulesCorePluginFile = new File(
10
+ providers.exec {
11
+ workingDir(rootDir)
12
+ commandLine(nodeBinary, "--print", "require.resolve('expo-modules-core/package.json')")
13
+ }.standardOutput.asText.get().trim(),
14
+ "../android/ExpoModulesCorePlugin.gradle"
15
+ )
16
+
17
+ apply from: expoModulesCorePluginFile
18
+ applyKotlinExpoModulesCorePlugin()
19
+ useCoreDependencies()
20
+ useExpoPublishing()
21
+
22
+ // If you want to use the managed Android SDK versions from expo-modules-core, set this to true.
23
+ // The Android SDK versions will be bumped from time to time in SDK releases and may introduce breaking changes in your module code.
24
+ // Most of the time, you may like to manage the Android SDK versions yourself.
25
+ def useManagedAndroidSdkVersions = false
26
+ if (useManagedAndroidSdkVersions) {
27
+ useDefaultAndroidSdkVersions()
28
+ } else {
29
+ buildscript {
30
+ // Simple helper that allows the root project to override versions declared by this library.
31
+ ext.safeExtGet = { prop, fallback ->
32
+ rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
33
+ }
34
+ }
35
+ project.android {
36
+ compileSdkVersion safeExtGet("compileSdkVersion", 34)
37
+ defaultConfig {
38
+ minSdkVersion safeExtGet("minSdkVersion", 21)
39
+ targetSdkVersion safeExtGet("targetSdkVersion", 34)
40
+ }
41
+ }
42
+ }
43
+
44
+ android {
45
+ namespace "expo.modules.mobileconsentssdk"
46
+ defaultConfig {
47
+ versionCode 1
48
+ versionName "0.1.0"
49
+ }
50
+ lintOptions {
51
+ abortOnError false
52
+ }
53
+ }
54
+
55
+ dependencies {
56
+ implementation 'androidx.activity:activity-compose:1.8.2'
57
+ implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4"
58
+
59
+ // Cannot upgrade further as the latest architecture (3.0.x) does not expose the ability to accept all consents.
60
+ implementation "com.cookieinformation:mobileconsents:3.0.1"
61
+ implementation "com.cookieinformation:core:0.0.13"
62
+
63
+ // Add these Compose Material3 dependencies
64
+ implementation "androidx.compose.material3:material3:1.1.2"
65
+ implementation "androidx.compose.material3:material3-window-size-class:1.1.2"
66
+ implementation "androidx.compose.ui:ui:1.4.3"
67
+ }
@@ -0,0 +1,2 @@
1
+ <manifest>
2
+ </manifest>