Quick Links
Hybrid Integration Tutorials Hybrid applcation bridge for iOS APIs

Tealeaf supports both UIWebView and WKWebView classes that iOS hybrid applications use.

Note: Apple recommends using WKWebView class instead of using UIWebView (https://developer.apple.com/documentation/uikit/uiwebview). You can view our sample code here: https://github.com/ibm-watson-cxa/SampleCode_Tealeaf_iOS_WebExample.

The known supported iOS frameworks:

You are required to instrument the HTML application with IBM Tealeaf UI Capture library to obtain all the interactions and behaviors of the web application placed into the webview. See the Tealeaf UI Capture library for more information.
Tealeaf automatically injects our JavaScript bridge that communicates with the web application posted using the native application. You are also required to upload the web application assets used in conjunction to replay the user sessions.


Hybrid integration tutorials

  • Instrumenting the web application

    You must instrument the UI Capture JavaScript library. Follow the Configuring DOM Capture and Replay for Hybrid applications tutorial.

  • Instrumenting the native application

    Note: The WebView might load at different times based on device and network, the TealeafLayoutConfig.json needs edited to capture layout when the WebView actually fires the page-loaded event. For an up-to-date example with four view controllers, see the sample code here: https://github.com/ibm-watson-cxa/SampleCode_Tealeaf_iOS_WebExample/blob/master/WebExample/WebExample/TLFResources.bundle/TealeafLayoutConfig.json. Three of the view controllers have WebViews.

    The file will look like the following:

    {
        "AutoLayout": {
            "StartViewController": {
                "do": true,
                "screenViewName": "StartViewController",
                "delay": 100,
                "takeScreenShot": false,
                "isWebView": false,
                "numberOfWebviews": 0
            },
            "SingleWebPageViewController": {
                "do": true,
                "screenViewName": "SingleWebPageViewController",
                "delay": 500,
                "takeScreenShot": false,
                "isWebView": true,
                "numberOfWebviews": 1
            },
            "DoubleWebPageViewController": {
                "do": true,
                "screenViewName": "DoubleWebPageViewController",
                "delay": 500,
                "takeScreenShot": false,
                "isWebView": true,
                "numberOfWebviews": 2
            },
            "WEWKWebViewController": {
                "do": true,
                "screenViewName": "WEWKWebViewController",
                "delay": 500,
                "takeScreenShot": false,
                "isWebView": true,
                "numberOfWebviews": 1
            }
        },
        "AppendMapIds": {
            "[w,9290],[v,0]": {
                "mid": "ASimpleUIView"
            },
            "tag2999999": {
                "mid": "giveAdditionalId1"
            },
            "idxPathValue": {
                "mid": "giveAdditionalId2"
            }
        }
    }
    	

    You will notice that StartViewController does not have a WebView because isWebView is set to false and numberOfWebviews is set to 0. This means that the entire view controller is captured 500 milliseconds after the view controller has loaded.

    SingleWebPageViewController uses one UIWebView because isWebView is set to true, numberOfWebviews is set to 1, do is set to true, and delay is set to 500. This means that the entire view controller is captured 500 milliseconds after the WebView has loaded.

    DoubleWebPageViewController uses two UIWebViews on the same view controller because isWebView is set to true, numberOfWebviews is set to 2, do is set to true, and delay is set to 500. This means the entire view controller is captured 500 milliseconds after all the WebViews have loaded.

    WEWKWebViewController uses one WKWebView on the same view controller because isWebView is set to true, numberOfWebviews is set to 1, do is set to true, and delay is set to 500. This means that the entire view controller is captured 500 milliseconds after the WebView has loaded.

    If you do not know the name of the view controller, you can create a session. Then review the session on the portal and look at the menu panel for the name of the view controller.

    For example:

  • Managing hybrid assets

    You can use the Find Hybrid Package feature to manage the assets that are required to replay a hybrid mobile application.


Hybrid application bridge for iOS APIs

For hybrid applications, applications that are both web and iOS applications, Tealeaf provides a hybrid bridge. The hybrid bridge is a series of APIs that allow JavaScript to call native iOS Tealeaf SDK APIs directly. With the hybrid bridge, you need to integrate the Tealeaf UI Capture JavaScript SDK with your application.

Hybrid Bridge APIs
TLFApplicationHelper iOS APIs TLFCustomEvent iOS APIs iOS APIs with existing JavaScript APIs


TLFApplicationHelper iOS APIs available to JavaScript

These TLFApplicationHelper iOS APIs are available to JavaScript developers:

  • – (void) enableTealeafFramework;
  • – (void) disableTealeafFramework;
  • – (void) requestManualServerPost;
  • – (BOOL) startNewTLFSession;
  • – (NSString*) currentSessionId;
  • – (BOOL) setConfigurableItem: (NSString*) configItem
    value: (id) value;
  • – (id) valueForConfiguralbeItem: (NSString*) configItem;
  • – (id) defaultValueForConfigurableItem: (NSString*) value
    forName: (NSString*) name;

The TLFApplicationHelper shared instance is available as the tealeafNativeApplicationHelperSharedInstance.

Example: How TLFApplicationHelper iOS API is invoked

This example shows how a native iOS API, – (void) enableTealeafFramework;, is invoked on a shared TLFApplicationHelper instance:

tealeafNativeApplicationHelperSharedInstance.enableTealeafFramework();
	


TLFCustomEvent iOS APIs available to JavaScript

These TLFCustomEvent iOS APIs are available to JavaScript developers:

  • – (BOOL) logEvent: (NSString*) eventName;
  • – (BOOL) logEvent: (NSString*) eventName
    values: (NSDictionary*) values;
  • – (BOOL) logPrintScreenEvent;

The TLFCustomEvent shared instance is available as the tealeafNativeCustomEventSharedInstance.

Example: How TLFCustomEvent iOS API is invoked

This example shows how a native iOS API, – (BOOL) logEvent: (NSString*) eventName, is invoked on a shared TLFCustomEvent instance:

tealeafNativeCustomEventSharedInstance.logEvent('Test iOS7 Bridge Event');
	


Using iOS APIs with existing JavaScript APIs

Two APIs that are part of the UI Capture j2 library are used in the hybrid bridge:

  • TLT.logScreenCapture instructs the underlying native functionality to take a screen capture.
  • TLT.registerBridgeCallbacks is used to register callback functions that are invoked by the UI Capture j2 library in specific instances. This API supports messageRedirect, screenCapture, and addRequestHeaders callbacks.
    • The messageRedirect callback can be registered to redirect and intercept messages from UI Capture j2.
    • The screenCapture callback can be registered to enable a JavaScript API to allow a screen capture to be taken.
    • The addRequestHeaders callback can be registered to enable a third-party JavaScript to return custom HTTP headers that need to be set on the UI Capture libraries POST request.

Example: Function call for all of the iOS native APIs

This function in this example, function runiOS7BridgeNativeTealeafAPIs (), shows how to call all of the iOS native APIs:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
 http://code.jquery.com/jquery-1.8.1.js   
    
	
<head> 
    http://tealeaf.concat.js
    <title>test APIs</title>
    <body>
        <h2>Test page for API Testing</h2>
        
        <input type="button" style="width: 300px; height: 60px; font-size: 30px"  value="Screen Capture" onclick="TLT.logScreenCapture();return false;"/>
        <p/>
        <input type="button" style="width: 300px; height: 60px; font-size: 30px" value="Fire" onclick="TLT.provideRequestHeaders();return false;"/>
        <p/>
        <input type="button" style="width: 300px; height: 60px; font-size: 30px" value="Native APIs" onclick="runiOS7BridgeNativeTealeafAPIs();return false;"/>
        <p/>
        

        
        
    </body>
	
	
	

function register_ScreenShot_Enable_CallBack() { 
TLT.registerBridgeCallbacks([
      {
          enabled: true,
          cbType: "screenCapture",
          cbFunction: myCbFunction1
      },
      {
          enabled: true,
          cbType: "messageRedirect",
          cbFunction: myCbFunction2
      },
      {
          enabled: true,
          cbType: "addRequestHeaders",
          cbFunction: myCbFunction3
      },
  ]);
}

function myCbFunction1() {
  alert("screen Capture by native");
}

function myCbFunction2(dataSent) {
  var div = document.getElementById('queueData');
  div.innerHTML = div.innerHTML + dataSent + 'n';
}

function myCbFunction3() {
  alert("add headers to native");
}

function htmlConsoleLog(textData, apiRetVal){
    var para = document.createElement("p");
    var node;
    if( apiRetVal !== undefined && apiRetVal !== null )
    {
        node = document.createTextNode(textData + " returned: " + apiRetVal);
    }
    else
    {
        node = document.createTextNode(textData );
    }
    para.appendChild(node);
    var element = document.getElementById("queueData");
    element.appendChild(para);
}

function runiOS7BridgeNativeTealeafAPIs() {
    htmlConsoleLog( '----- -------------------------------- -----' );
    htmlConsoleLog( '----- Calling Tealeaf native APIs -----' );

    var apiRetVal = null;
    htmlConsoleLog( '----- Calling enableTealeaf -----' );
    tealeafNativeApplicationHelperSharedInstance.enableTealeafFramework();
    
    apiRetVal = null;
    htmlConsoleLog( '----- Calling currentSessionId -----' );
    apiRetVal = tealeafNativeApplicationHelperSharedInstance.currentSessionId();
    htmlConsoleLog( '----- currentSessionId -----', apiRetVal );
    
    apiRetVal = null;
    htmlConsoleLog( '----- Calling disableTealeaf -----' );
    tealeafNativeApplicationHelperSharedInstance.disableTealeafFramework();
    
    apiRetVal = null;
    htmlConsoleLog( '----- Calling defaultValueForConfigurableItem(PostMessageUrl) -----' );
    var PostMessageUrlVal = tealeafNativeApplicationHelperSharedInstance.defaultValueForConfigurableItem('PostMessageUrl');
    htmlConsoleLog( '----- defaultValueForConfigurableItem -----', PostMessageUrlVal );
    
    apiRetVal = null;
    htmlConsoleLog( '----- Calling setConfigurableItemValue("PostMessageUrl", "blahblah") -----' );
    apiRetVal = tealeafNativeApplicationHelperSharedInstance.setConfigurableItemValue('PostMessageUrl', 'blahblah');
    htmlConsoleLog( '----- setConfigurableItemValue -----', apiRetVal );
    
    apiRetVal = null;
    htmlConsoleLog( '----- Calling valueForConfigurableItem("PostMessageUrl") -----' );
    apiRetVal = tealeafNativeApplicationHelperSharedInstance.valueForConfigurableItem('PostMessageUrl');
    htmlConsoleLog( '----- valueForConfigurableItem -----', apiRetVal );
    
    apiRetVal = null;
    htmlConsoleLog( '----- Calling setConfigurableItemValue("PostMessageUrl", '+ PostMessageUrlVal + ') -----' );
    apiRetVal = tealeafNativeApplicationHelperSharedInstance.setConfigurableItemValue('PostMessageUrl', PostMessageUrlVal );
    htmlConsoleLog( '----- setConfigurableItemValue -----', apiRetVal );

    apiRetVal = null;
    htmlConsoleLog( '----- Calling valueForConfigurableItem("PostMessageUrl") -----' );
    apiRetVal = tealeafNativeApplicationHelperSharedInstance.valueForConfigurableItem('PostMessageUrl');
    htmlConsoleLog( '----- valueForConfigurableItem -----', apiRetVal );

    apiRetVal = null;
    htmlConsoleLog( '----- Calling startNewTLFSession -----' );
    apiRetVal = tealeafNativeApplicationHelperSharedInstance.startNewTLFSession();
    htmlConsoleLog( '----- startNewTLFSession -----', apiRetVal );

    apiRetVal = null;
    htmlConsoleLog( '----- Calling enableTealeaf again -----' );
    tealeafNativeApplicationHelperSharedInstance.enableTealeafFramework();

    apiRetVal = null;
    htmlConsoleLog( '----- Calling currentSessionId -----' );
    apiRetVal = tealeafNativeApplicationHelperSharedInstance.currentSessionId();
    htmlConsoleLog( '----- currentSessionId -----', apiRetVal );

    apiRetVal = null;
    htmlConsoleLog( '----- Calling logPrintScreenEvent -----' );
    apiRetVal = tealeafNativeCustomEventSharedInstance.logPrintScreenEvent();
    htmlConsoleLog( '----- logPrintScreenEvent -----', apiRetVal );

    apiRetVal = null;
    htmlConsoleLog( '----- Calling logEvent("Test iOS7 Bridge Event") -----' );
    apiRetVal = tealeafNativeCustomEventSharedInstance.logEvent('Test iOS7 Bridge Event');
    htmlConsoleLog( '----- logEvent -----', apiRetVal );

    apiRetVal = null;
    htmlConsoleLog( '----- Calling logEventValues("Test iOS7 Bridge Event", objDict) -----' );
    var objDict = {'key1iOS7Bridge': 'value11iOS7Bridge', 'key21iOS7Bridge': 'value21iOS7Bridge'};
    apiRetVal = tealeafNativeCustomEventSharedInstance.logEventValues('Test iOS7 Bridge Event', objDict);
    htmlConsoleLog( '----- logEventValues(Test iOS7 Bridge Event, objDict ) -----', apiRetVal );

    htmlConsoleLog( '----- Done Calling Tealeaf native APIs -----' );
    htmlConsoleLog( '----- -------------------------------- -----' );
    htmlConsoleLog( '----- -------------------------------- -----' );
    htmlConsoleLog( '----- -------------------------------- -----' );
}

//runiOS7BridgeNativeTealeafAPIs();

register_ScreenShot_Enable_CallBack();

	
	
</head>

</html>
	

Join The Discussion

Your email address will not be published. Required fields are marked *