Hybrid applications for iOS

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

📘

Note:

Apple recommends using WKWebView class instead of using UIWebView. You can view our sample code here: SampleCode_Tealeaf_iOS_WebExample

The known supported iOS frameworks:

You are required to instrument the HTML application with Acoustic Tealeaf Web SDK to obtain all the interactions and behaviors of the web application placed into the webview. See the Tealeaf Web SDK 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

📘

Note:

DOM diff is supported only in Tealeaf SaaS. In Tealeaf On-premises, DOM diff is supported for web-only and not supported for replaying Hybrid Mobile apps.

📘

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: SDK_Tools -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:

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 Web SDK JavaScript SDK with your application.

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 Web SDK 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 Web SDK 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 Web SDK 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 Web SDK 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>