- What we are aiming for
- How to Install the CMP SDK
- The support CmpViewController
- Load the First Layer Message
- Load the Privacy Manager
- The full example IOS project
The purpose of this document is to show you how to integrate our SDK in a ReactNative application using a test property, at the end you'll have the following result
In the Podfile of the ReactNative IOS project, add the CMP framework dependence to your app target:
target 'CmpReactNativeIntegration' do
...
pod 'ConsentViewController', 'X.Y.Z'
...
endand then execute
pod installIn order to use the capabilities of our Cmp Framework, it is necessary to use a support ViewController within which adding
the framework configuration. The CmpViewController simply extends the standard UIViewController with the consent functions.
import Foundation
import ConsentViewController
class CmpViewController: UIViewController {
lazy var consentManager: SPConsentManager = { SPConsentManager(
accountId: 22,
propertyName: try! SPPropertyName("mobile.multicampaign.demo"),
campaignsEnv: .Public, // optional - Public by default
campaigns: SPCampaigns(
gdpr: SPCampaign(), // optional
ccpa: SPCampaign(), // optional
ios14: SPCampaign() // optional
),
delegate: self
)}()
override func viewDidLayoutSubviews() {
consentManager.cleanUserDataOnError = false
consentManager.loadMessage()
}
}
protocol RNSPDelegate : SPDelegate{} // used for objc - swift compatibility
extension CmpViewController: RNSPDelegate {
func onSPUIReady(_ controller: UIViewController) {
controller.modalPresentationStyle = .overFullScreen
present(controller, animated: true)
}
func onAction(_ action: SPAction, from controller: UIViewController) {
print(action)
action.publisherData = ["foo": "action"]
print(action)
}
func onSPUIFinished(_ controller: UIViewController) {
// updateIDFAStatusLabel()
dismiss(animated: true)
}
func onConsentReady(userData: SPUserData) {
print("onConsentReady:", userData)
// let vendorAccepted = userData.gdpr?.consents?.vendorGrants[myVendorId]?.granted ?? false
// updateMyVendorUI(vendorAccepted)
// updatePMButtons(ccpaApplies: consentManager.ccpaApplies, gdprApplies: consentManager.gdprApplies)
}
func onSPFinished(userData: SPUserData) {
print("SDK DONE")
}
func onError(error: SPError) {
print("Something went wrong: ", error)
}
}
// MARK: - UI methods
extension MyViewController {
func updateIDFAStatusLabel() {
}
func updateMyVendorUI(_ accepted: Bool) {
}
func updatePMButtons(ccpaApplies: Bool, gdprApplies: Bool) {
}
}The CmpViewController source is available here.
Now that the support CmpViewController is ready, it's the moment to replace the standard UIViewController. In the
AppDelegate.mm file you should import the Cmp Framework
#import "CmpReactNativeIntegration-Swift.h"and then add the support CmpViewController just created. Find and replace the following line
UIViewController *rootViewController = [UIViewController new];with this:
CmpViewController *rootViewController = [CmpViewController new];You can find here
the final AppDelegate.mm file.
The FLM requires is triggered invoking the loadMessage from the viewDidLayoutSubviews callback
override func viewDidLayoutSubviews() {
//...
consentManager.loadMessage()
//...
}The surfacing process of a PM involve the communication between the common ReactNative layer and the mobile native part. To overcome the cross-platform communication challenge we make use of the Native Modules
The first step, is the creation of the function that you need on native part like an implementation on native apps. We will create a file called SpModule.swift on ios folder from our React Native app.
The SpModule.swift has all the functions that we need to expose to the Javascript side. In our example, we have three
buttons, two of them surface a GDPR and a CCPA Privacy Manager and one of them is clearing the saved local data:
showCcpaPm: surfaces the CCPA PM,showGdprPm: surfaces the GDPR PM,clearData: deletes local data.
Moreover, we need to implement a requiresMainQueueSetup function to manage our queue on main thread.
import Foundation
import ConsentViewController
@objc(SpModule)
class SpModule : NSObject {
@objc static func requiresMainQueueSetup() -> Bool {
return false
}
@objc
func clearData() -> Void { }
@objc
func showCcpaPm() -> Void { }
@objc
func showGdprPm() -> Void { }
}Note that we add @objc for the module and all its function, this means that this module and those functions will be
called on Objective-C and you need these declarations to work as expected.
To expose our swift module to the Javascript side we need an obj-c bridge to connect the two worlds. Following the Objective-C
instance you need:
#import <Foundation/Foundation.h>
#import "React/RCTBridgeModule.h"
#import <React/RCTUtils.h>
@interface RCT_EXTERN_MODULE(SpModule, NSObject)
RCT_EXTERN_METHOD(showGdprPm)
RCT_EXTERN_METHOD(clearData)
RCT_EXTERN_METHOD(showCcpaPm)
@endRCT_EXTERN_MODULEis used to declare the module,RCT_EXTERN_METHODis used to make available a function from the Javascript files.
To be able to execute the native methods, we need to use the NativeModules from react-native.
In your App.js file import the module that we just created:
import { NativeModules } from 'react-native';
const { SpModule } = NativeModules;Now you can invoke the functions using the SpModule object as follows:
// ...
<Button title="Show GDPR Privacy Manager" onPress={() => SpModule.showGdprPm() } />
<Button title="Show CCPA Privacy Manager" onPress={() => SpModule.showCcpaPm() } />
<Button title="Clear All Data" onPress={() => SpModule.clearData() } />
// ...In this scenario the main obstacle is that the SpModule doesn't have any instance of our cmp SDK, the SDK reference
is in CmpViewController. To establish the communication between the SpModule and the CmpViewController, we can use
a notification dispatch mechanism for broadcasting information to the registered observers, the NotificationCenter.
Following the full SpModule
import Foundation
import ConsentViewController
@objc(SpModule)
class SpModule : NSObject {
@objc static func requiresMainQueueSetup() -> Bool {
return false
}
@objc
func clearData() -> Void {
SPConsentManager.clearAllData()
}
@objc
func showCcpaPm() -> Void {
NotificationCenter.default.post(
name: UIApplication.willEnterForegroundNotification,
object: "ccpa"
)
}
@objc
func showGdprPm() -> Void {
NotificationCenter.default.post(
name: UIApplication.willEnterForegroundNotification,
object: "gdpr"
)
}
}Follows the configuration for receiving the message in the CmpViewController and surfacing the PM, here the full source.
class CmpViewController: UIViewController {
deinit {
NotificationCenter.default.removeObserver(
self,
name: UIApplication.willEnterForegroundNotification,
object: nil
)
}
// ...
override func viewDidLayoutSubviews() {
...
NotificationCenter.default.addObserver(
self,
selector: #selector(CmpViewController.pm(notification:)),
name: UIApplication.willEnterForegroundNotification,
object: nil
)
}
@objc func pm(notification: Notification){
let type = notification.object as? String ?? ""
if type.contains("gdpr") {
showGdprPm()
}else if type.contains("ccpa"){
showCcpaPm()
}
}
func showGdprPm() {
DispatchQueue.main.async {
self.consentManager.loadGDPRPrivacyManager(withId: "488393")
}
}
func showCcpaPm() {
DispatchQueue.main.async {
self.consentManager.loadCCPAPrivacyManager(withId: "509688")
}
}
}

