WebView Tracking
    • 3 Minutes to read
    • Dark
      Light

    WebView Tracking

    • Dark
      Light

    Article summary

    Unlike native Android and iOS, React Native doesn’t provide a built-in VebView. A list of official react-native components can be found in the official documentation. The old component is deprecated and official documentation recommends not using it. Instead, they recommend using the community WebView component.

    Bi-directional communication

    Mobile applications use a WebView component to load some Web pages. In many use cases it is required to call some function from “native“ mobile code to a Web JavaScript code (named: call JavaScript from native), and also to call and execute some function from a Web page’s JavaScript code to a mobile native code (named: call native from JavaScript). So, to provide rich functionality in the mobile application that loads some web content via the WebView component, we must handle this communication between two ends.

    On the native Android and iOS, native components are flexible to support multiple methods with user-defined names.

    WebView for React Native is implemented with two predefined methods that should be used for this communication:

    1. injectJavaScript(String) - function used to call JavaScript from native

    2. postMessage(String) - function used to call native from JavaScript

    Tracking implementation on the native Android and iOS

    The current implementation for WebView tracking, on the native Android and iOS components (native WebView for Android, and WKWebView for iOS) has 4 defined methods for call native from JavaScript communication:

    1. getEverId():String

    2. trackCustomPage(pageName: String, params: String)

    3. trackCustomEvent(eventName: String, params: String)

    4. getUserAgent(): String

    Problem with React-native WebView tracking

    ReactNative WebView has a single method to be called from JavaScript and can pass only a single parameter. We can not have multiple predefined methods, nor can multiple parameters be passed to a method.

    A possible solution is to call postMessage(String) where we are going to pack all required data in a JSON stringified form.

    let message = JSON.stringify( 
       { 
            'method': 'trackCustomPage', 
            'name':'Some random value', 
            'params':'Another random value' 
       } 
    );
    window.ReactNativeWebView.postMessage(message);

    Then, on the React Native code, the callback function onMessage(WebViewMessageEvent) is triggered. Here we can check the event and passed data:

    const onMessage = (event: WebViewMessageEvent) => { 
         const json = JSON.parse(event.nativeEvent.data); 
         const method = json.method; 
         const name = json.name; 
         const params = json.params; 
    
         console.log(method, name, params); 
    // execute native plugin method(s)
    };

    Current implementation and changes for React Native

    In the current sample for WebView tracking, for native platforms (Android, iOS) we have the following function to call trackCustomPage and pass two arguments (name = 'test', params= 'test'):

    window.WebtrekkAndroidWebViewCallback.trackCustomPage('test', 'test');

    As we can't call functions with user-defined names and can only pass a single argument of String type, then to execute a similar call for React Native, we can use postMessage:

    const data={ method: 'trackCustomPage', 'name':'test', 'params':'test' }; 
    const message=JSON.stringify(data);
    window.ReactNativeWebView.postMessage(message);

    In this way, React Native application can distinguish between different methods, and execute proper action.

    Injecting EverId to the page as a variable

    As we can not get results from a calling method, the web page can’t use the getEverId() method and get value. Instead, we need to inject the everId into the loaded web page, so that the pixel can grab and use that value further. To inject everId into the page's variable webtrekkApplicationEverId:

    // define a script to be executed from the React Native
    // in the execution time we will replace placeholder %everId% with a real value 
    const injectEverIdScript = `window.webtrekkApplicationEverId = '%everId%' ; true; `; 
    
    // after that, we need to execute the defined JS script 
    // first, we need to get current everId from Mapp plugin 
    // and to replace placeholder in the script with actual value 
    
    MappIntelligencePlugin.getEverId() 
       .then((everId: string) => { 
          if (webViewRef.current) { 
             const scripts = injectEverIdScript.replace('%everId%', everId); 
             webViewRef.current.injectJavaScript(scripts); 
          } 
       }) 
       .catch((error: Error) => { 
         console.error(error); 
         MappIntelligencePlugin.trackException(error);
       });

    Currently, from the React Native side, we can check if the variable is successfully injected. This can be done in the following steps:

    1. create a script to (re)define the function getEverId() on the web page

      const script=` 
           window.WebtrekkAndroidWebViewCallback.getEverId = function(){ 
                window.ReactNativeWebView.postMessage( 
                     JSON.stringify({ 
                        'method': 'getEverId', 
                        'name':'webtrekkApplicationEverId', 
                        'params': window.webtrekkApplicationEverId 
                     }) 
                ); 
           }
      `

    2. Inject this script in the injectedJavaScript event of a WebView, or on some other event.

    3. After that, we can call that injected method which will return the value of the injected webtrekkApplicationEverId

      setTimeout(() => { 
           webViewRef.current?.injectJavaScript( 
                `window.WebtrekkAndroidWebViewCallback.getEverId()` 
           );
      }, 1000);

    4. In the onMessage() callback we can define logic for this method, check the received value, and compare it with the one that was injected.


    Was this article helpful?