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:
- Ionic 3.0 - https://ionicframework.com/docs/
You can view our sample code here: SampleIonic. - Cordova 7.0 - https://cordova.apache.org
You can view our sample code here:
SampleCordova .
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
- Instrumenting the web application
You must instrument the Web SDK JavaScript library. Follow the Configuring DOM Capture and Replay for Hybrid applications tutorial.
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.
- Instrumenting the native application
If your application uses:- Objective C, then follow the Getting started with the Acoustic Tealeaf SDK for iOS using Objective C tutorial.
- Swift, then follow the Getting started with the Acoustic Tealeaf SDK for iOS using Swift tutorial.
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:
- Managing hybrid assets
You can use the Find Hybrid Package feature to manage the assets that are required to replay a hybrid mobile application.
For more information see [Manage the assets that are required for hybrid mobile app replay] (https://help.goacoustic.com/hc/en-us/articles/360043836334-Manage-the-assets-that-are-required-for-hybrid-mobile-app-replay)
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 supportsmessageRedirect
,screenCapture
, andaddRequestHeaders
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.
- The
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>
Updated 8 months ago