Synchronization of deviceUUID between React Native mobile SDK and JS SDK in a WebView-enabled app
You've successfully completed this step, if:In the Maestra control panel, a single customer card is created, capturing actions from both mobile SDK and website JS SDK.
1. Add a method to get deviceUUID
// Set a suitable timeout for deviceUUID retrieval
// If deviceUUID retrieval is not completed during first initialization
// synchronization will occur on next page load or app launch
// When using third-party cookies, ensure you wait for deviceUUID retrieval
// otherwise synchronization will not occur
const MAX_UUID_WAIT_TIME = Platform.OS === 'ios' ? 250 : 4000;
// Function to await deviceUUID retrieval within MAX_UUID_WAIT_TIME
const waitForDeviceUUID = (timeout) => {
return new Promise((resolve, reject) => {
const timeoutHandler = setTimeout(() => {
console.log('Device UUID not received within timeout');
reject(new Error('Device UUID not received within timeout'));
}, timeout);
MindboxSdk.getDeviceUUID((uuid) => {
console.log('Device UUID received:', uuid);
clearTimeout(timeoutHandler);
if (uuid) {
resolve(uuid);
} else {
reject(new Error('Device UUID is empty or undefined'));
}
});
});
};
During first Mindbox SDK initialization on Android, deviceUUID may take several seconds to be retrievedIn subsequent initializations, deviceUUID is retrieved within 100-200 ms
2. Add code to await deviceUUID retrieval before page load in useEffect
useEffect(() => {
// Attempt to fetch mobile deviceUUID within specified timeout (MAX_UUID_WAIT_TIME)
// Page loading starts either upon UUID receipt or timeout expiration
// If UUID cannot be retrieved, synchronization occurs on next page load/app launch
const initialize = async () => {
try {
console.log('Starting waitForDeviceUUID...')
const uuid = await waitForDeviceUUID(MAX_UUID_WAIT_TIME)
setDeviceUUID(uuid)
// Start loading the page
setCanLoadWebView(true)
console.log('Completed waitForDeviceUUID, Device UUID:', uuid)
} catch (error) {
// Even if retrieving the deviceUUID times out during the first page load,
// synchronization will occur on subsequent page loads or app launches.
MindboxSdk.getDeviceUUID((uuid) => {
setDeviceUUID(uuid)
console.log('Device UUID retrieved after timeout:', uuid)
})
setCanLoadWebView(true)
}
}
// Initialize the Mindbox SDK
const appInitializationCallback = async () => {
try {
await MindboxSdk.initialize(configuration)
} catch (error) {
console.log(error)
}
}
appInitializationCallback()
initialize()
}, [])3. Add a method to synchronize deviceUUID between the mobile SDK and JS SDK
// Function to synchronize deviceUUID with JS SDK
const synchronizeDeviceUUID = (uuid) =>
try {
const deviceUUID = '${uuid || ''}';
if (deviceUUID) {
document.cookie = "mindboxDeviceUUID=" + deviceUUID;
localStorage.setItem('mindboxDeviceUUID', deviceUUID);
window.ReactNativeWebView.postMessage(JSON.stringify({ status: 'successSync' }));
} else {
window.ReactNativeWebView.postMessage(JSON.stringify({ status: 'errorSync', message: 'deviceUUID is null or undefined' }));
}
} catch (error) {
window.ReactNativeWebView.postMessage(JSON.stringify({ status: 'errorSync', message: error.message }));
}4. In the WebView component, use the synchronizeDeviceUUID method
return (
<SafeAreaView style={styles.container}>
{canLoadWebView ? (
<>
<WebView style={{ flex: 1 }} ref={webViewRef} source={{ uri: webViewUrl }}
javaScriptEnabled={true}
domStorageEnabled={true}
injectedJavaScriptBeforeContentLoaded={synchronizeDeviceUUID(deviceUUID)}
onMessage={onMessage} />
<View style={styles.buttonContainer}>
<Button title="Show Data" onPress={showData} />
</View>
</>
) : (
<View style={styles.loadingContainer}>
<ActivityIndicator size="large" color="#0000ff" />
<Text>Waiting for Device UUID...</Text>
</View>
)}
</SafeAreaView>
)Debugging
1. In the onMessage callback, handle messages from WebView
// Handler for messages received from WebView
const onMessage = (event) => {
const data = JSON.parse(event.nativeEvent.data)
// Use the switch statement to handle different cases
switch (data.status) {
case 'errorSync':
console.error('JavaScript execution error:', data.message)
break
case 'successSync':
console.log('Synchronization successful.')
break
default:
if (data.cookies || data.deviceUUID) {
console.log('Cookies:', data.cookies)
console.log('Device UUID from JS SDK:', data.deviceUUID)
console.log('Device UUID from mobile SDK:', deviceUUID)
} else if (data.error) {
console.error('WebView error:', data.error)
} else {
console.log('Unhandled message:', data)
}
break
}
}2. Add a method for debugging synchronization
// Method for debugging synchronization.
// Displays the deviceUUID stored in cookies, localStorage, and the mobile deviceUUID.
// These deviceUUID values must match. Call after the page loads
const showData = () => {
if (!webViewRef.current) {
console.error('WebView is not initialized.')
return
}
const script = `
(function() {
try {
const cookies = document.cookie || 'No cookies found';
const deviceUUID = localStorage.getItem('mindboxDeviceUUID') || 'No deviceUUID found';
window.ReactNativeWebView.postMessage(JSON.stringify({
cookies,
deviceUUID
}));
} catch (error) {
window.ReactNativeWebView.postMessage(JSON.stringify({ error: error.message }));
}
})();
`
webViewRef.current.injectJavaScript(script)
}Example
import React, { useEffect, useState, useRef } from 'react'
import { SafeAreaView, StyleSheet, Text, View, Button, ActivityIndicator, Platform } from 'react-native'
import MindboxSdk, { LogLevel } from 'mindbox-sdk'
import { WebView } from 'react-native-webview'
// Configuration for Mindbox SDK initialization
const configuration = {
domain: 'api.mindbox.ru',
endpointId: Platform.OS === 'ios' ? 'your-ios-endpoint-system-name' : 'your-android-endpoint-system-name',
subscribeCustomerIfCreated: true,
shouldCreateCustomer: true,
}
// Timeout for waiting to fetch the deviceUUID.
// The page will not start loading until this timeout expires.
// During the first initialization on Android, fetching may take a few seconds,
// while subsequent attempts typically take less than 250 ms.
const MAX_UUID_WAIT_TIME = Platform.OS === 'ios' ? 250 : 4000
const HomeScreen = () => {
const [deviceUUID, setDeviceUUID] = useState(null)
const [canLoadWebView, setCanLoadWebView] = useState(false)
const webViewRef = useRef(null)
const webViewUrl = 'https://example.com'
// Function to synchronize deviceUUID with the JS SDK
const synchronizeDeviceUUID = (uuid) => `
try {
const deviceUUID = '${uuid || ''}';
if (deviceUUID) {
document.cookie = "mindboxDeviceUUID=" + deviceUUID;
localStorage.setItem('mindboxDeviceUUID', deviceUUID);
window.ReactNativeWebView.postMessage(JSON.stringify({ status: 'successSync' }));
} else {
window.ReactNativeWebView.postMessage(JSON.stringify({ status: 'errorSync', message: 'deviceUUID is null or undefined' }));
}
} catch (error) {
window.ReactNativeWebView.postMessage(JSON.stringify({ status: 'errorSync', message: error.message }));
}
`
// Handler for messages received from the WebView
const onMessage = (event) => {
const data = JSON.parse(event.nativeEvent.data)
// Using switch statement to handle different cases
switch (data.status) {
case 'errorSync':
console.error('JavaScript execution error:', data.message)
break
case 'successSync':
console.log('Synchronization successful.')
break
default:
if (data.cookies || data.deviceUUID) {
console.log('Cookies:', data.cookies)
console.log('Device UUID from JS SDK:', data.deviceUUID)
console.log('Device UUID from mobile SDK:', deviceUUID)
} else if (data.error) {
console.error('Error from WebView:', data.error)
} else {
console.log('Unhandled message:', data)
}
break
}
}
// Debugging method for synchronization.
// Displays the deviceUUID stored in cookies, localStorage, and the mobile device UUID.
// These values of deviceUUID should match.
const showData = () => {
if (!webViewRef.current) {
console.error('WebView is not initialized.')
return
}
const script = `
(function() {
try {
const cookies = document.cookie || 'No cookies found';
const deviceUUID = localStorage.getItem('mindboxDeviceUUID') || 'No deviceUUID found';
window.ReactNativeWebView.postMessage(JSON.stringify({
cookies,
deviceUUID
}));
} catch (error) {
window.ReactNativeWebView.postMessage(JSON.stringify({ error: error.message }));
}
})();
`
webViewRef.current.injectJavaScript(script)
}
useEffect(() => {
// Attempts to fetch the mobile device UUID within the specified timeout (MAX_UUID_WAIT_TIME).
// The page will start loading either as soon as the UUID is fetched or after the timeout expires.
// If the UUID cannot be fetched, synchronization will happen on the next page load or app launch.
const initialize = async () => {
try {
console.log('Starting waitForDeviceUUID...')
const uuid = await waitForDeviceUUID(MAX_UUID_WAIT_TIME)
setDeviceUUID(uuid)
setCanLoadWebView(true)
console.log('Finished waitForDeviceUUID, Device UUID:', uuid)
} catch (error) {
// Even if fetching the deviceUUID times out during the initial page load,
// synchronization will occur on subsequent page loads or app launches.
MindboxSdk.getDeviceUUID((uuid) => {
setDeviceUUID(uuid)
console.log('Device UUID received after timeout:', uuid)
})
setCanLoadWebView(true)
}
}
// Initialize the Mindbox SDK
const appInitializationCallback = async () => {
try {
await MindboxSdk.initialize(configuration)
} catch (error) {
console.log(error)
}
}
appInitializationCallback()
initialize()
MindboxSdk.setLogLevel(LogLevel.DEBUG)
MindboxSdk.getToken((token) => {
console.log('Token:', token)
})
MindboxSdk.getSdkVersion((version) => {
console.log('Sdk version:', version)
})
}, [])
// Fetches the deviceUUID within the specified timeout period.
// Note: The MAX_UUID_WAIT_TIME should not be set to less than 250 ms,
// as the deviceUUID might not be fetched in time.
const waitForDeviceUUID = (timeout) => {
return new Promise((resolve, reject) => {
const timeoutHandler = setTimeout(() => {
console.log('Device UUID not received within timeout')
reject(new Error('Device UUID not received within timeout'))
}, timeout)
MindboxSdk.getDeviceUUID((uuid) => {
console.log('Device UUID received:', uuid)
clearTimeout(timeoutHandler)
resolve(uuid)
})
})
}
return (
<SafeAreaView style={styles.container}>
{canLoadWebView ? (
<>
<WebView style={{ flex: 1 }} ref={webViewRef} source={{ uri: webViewUrl }}
javaScriptEnabled={true}
domStorageEnabled={true}
injectedJavaScriptBeforeContentLoaded={synchronizeDeviceUUID(deviceUUID)}
onMessage={onMessage} />
<View style={styles.buttonContainer}>
<Button title="Show Data" onPress={showData} />
</View>
</>
) : (
<View style={styles.loadingContainer}>
<ActivityIndicator size="large" color="#0000ff" />
<Text>Waiting for Device UUID...</Text>
</View>
)}
</SafeAreaView>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
loadingContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
buttonContainer: {
padding: 10,
backgroundColor: '#f0f0f0',
},
})
export default HomeScreen
Updated 6 months ago

