I have got Logic.js file from Metaio 3rd party sdk in my iOS Augmented reality based iOS project. This .JS file is created by Metaio creator.
I am modifying this file to call my iOS native web view. Basically, i want to call iOS native view from this .JS file.
Below is the Logic.js file used in the iOS project. Using window.location
i'm trying to call UIWebview delegate from this .JS file.
var methodExists = function (object, method) {
return typeof object !== 'undefined' && typeof method === 'function';
};
arel.sceneReady(function() {
var scenario = {};
scenario.objectName = "scenario";
scenario.contents = []; // Array of all contents in this AR scenario
scenario.trackables = []; // Array of all trackables in this AR scenario
scenario.scenes = []; // Array of all scenes in this AR scenario
scenario.googleAnalytics = null;
scenario.currentScene = null;
scenario.currentExperience360 = null;
scenario.instantTrackingMode = false; // True if instant tracking is currently running
scenario.currentTrackingConfigPathOrIdentifier = "html/resources/TrackingData.zip";
scenario.addObject = function (object) {
arel.Debug.log("scenario.addObject(" + object.objectName + ")");
this.registerObject(object);
arel.Scene.addObject(object);
};
scenario.registerObject = function (object) {
arel.Debug.log("scenario.registerObject(" + object.objectName + ")");
arel.Events.setListener(object, this.objectEventsCallback, scenario);
};
scenario.groupID = 0;
scenario.getNewGroupID = function () {
this.groupID++;
return this.groupID;
};
scenario.getTrackable = function (identifier) {
arel.Debug.log("scenario.getTrackable(" + identifier + ")");
var i;
var trackable = null;
if (!identifier || identifier === "") {
arel.Debug.log("scenario.getTrackable(): Warning - identifier is empty, returning null");
return trackable;
}
var allTrackables = this.trackables;
for (i = 0; i < allTrackables.length; ++i) {
trackable = allTrackables[i];
if (trackable.objectName == identifier) {
return trackable;
}
if (trackable.cosName == identifier) {
return trackable;
}
if (trackable.cosID == identifier) {
return trackable;
}
}
arel.Debug.log("scenario.getTrackable(" + identifier + "): Error - could not correlate the given identifier to any known trackable.");
return null;
};
scenario.sceneCallback = function (type, result) {
if (!type) {
return;
}
switch (type) {
case arel.Events.Scene.ONTRACKING:
this.onTrackingChanged(result);
break;
case arel.Events.Scene.ONVISUALSEARCHRESULT:
break;
case arel.Events.Scene.ONREADY:
break;
case arel.Events.Scene.ONLOAD:
case arel.Events.Scene.ONLOCATIONUPDATE:
default:
break;
}
};
scenario.objectEventsCallback = function (object, type, params) {
switch (type) {
case arel.Events.Object.ONREADY:
if (methodExists(object, object.onLoaded)) {
object.onLoaded();
}
break;
case arel.Events.Object.ONTOUCHSTARTED:
if (this.googleAnalytics) {
this.googleAnalytics.logUIInteraction(arel.Plugin.Analytics.Action.TOUCHSTARTED, object.getID());
}
break;
case arel.Events.Object.ONTOUCHENDED:
if (this.googleAnalytics) {
this.googleAnalytics.logUIInteraction(arel.Plugin.Analytics.Action.TOUCHENDED, object.getID());
}
break;
case arel.Events.Object.ONINVISIBLE:
case arel.Events.Object.ONVISIBLE:
case arel.Events.Object.ONANIMATIONENDED:
case arel.Events.Object.ONMOVIEENDED:
case arel.Events.Object.ONLOAD:
case arel.Events.Object.ONROTATED:
case arel.Events.Object.ONSCALED:
case arel.Events.Object.ONTRANSLATED:
default:
break;
}
};
scenario.onTrackingChanged = function (trackingValuesList) {
if (trackingValuesList.length === 0) {
arel.Debug.log("scenario.onTrackingChanged: Error - list of tracking values is empty, this should be impossible.");
return;
}
var i, trackingValues, cosName, cosID, trackable, trackingMethod, gaTrackingMethod;
for (i = 0; i < trackingValuesList.length; i++) {
trackingValues = trackingValuesList[i];
trackable = null;
cosName = trackingValues.getCoordinateSystemName();
cosID = trackingValues.getCoordinateSystemID();
// Try to find the trackable by its COS name first. If that fails, try the COS ID.
if (cosName && cosName !== "") {
trackable = this.getTrackable(cosName);
}
if (trackable === null && cosID) {
trackable = this.getTrackable(cosID);
}
if (trackable === null) {
arel.Debug.log("onTrackingChanged: Error - Can't find a trackable matching COS name '" + cosName + "' or COS ID '" + cosID + "'");
return;
}
else {
// The cosID 1 is strictly reserved for the 360 experience if it is running.
if (scenario.currentExperience360 && cosID === 1) {
return;
}
}
switch (trackingValues.getState()) {
case arel.Tracking.STATE_NOTTRACKING:
arel.Debug.log("onTrackingChanged: " + trackable.objectName + " is not tracking");
if (methodExists(trackable, trackable.onTrackingLost)) {
trackable.onTrackingLost(trackingValues);
}
break;
case arel.Tracking.STATE_TRACKING:
arel.Debug.log("onTrackingChanged: " + trackable.objectName + " is tracking");
if (methodExists(trackable, trackable.onDetected)) {
trackable.onDetected();
}
if (methodExists(trackable, trackable.onTracked)) {
trackable.onTracked(trackingValues);
}
if (this.googleAnalytics) {
trackingMethod = trackingValues.getType();
gaTrackingMethod = this.googleAnalytics.trackingTypeToAnalyticsType(trackingMethod);
this.googleAnalytics.logTrackingEvent(gaTrackingMethod, arel.Plugin.Analytics.Action.STATE_TRACKING, cosID, cosName);
}
break;
case arel.Tracking.STATE_EXTRAPOLATED:
case arel.Tracking.STATE_INITIALIZED:
case arel.Tracking.STATE_REGISTERED:
default:
break;
}
}
};
scenario.startInstantTracking = function () {
arel.Debug.log("scenario.startInstantTracking()");
if (this.instantTrackingMode) {
return;
}
this.instantTrackingMode = true;
if (scenario.currentExperience360) {
scenario.currentExperience360.hide();
}
// Iterate over all trackables, simulate an onTrackingLost() for all those which are currently tracking.
var i, trackable;
for (i = 0; i < this.trackables.length; ++i) {
trackable = this.trackables[i];
if (trackable.isCurrentlyTracking && trackable != userDevice) {
if (methodExists(trackable, trackable.onTrackingLost)) {
trackable.onTrackingLost();
}
}
}
arel.Scene.startInstantTracking(arel.Tracking.INSTANT2D);
if (methodExists(this, this.onStartInstantTracking)) {
this.onStartInstantTracking();
}
};
scenario.stopInstantTracking = function () {
arel.Debug.log("scenario.stopInstantTracking()");
if (!this.instantTrackingMode) {
return;
}
this.instantTrackingMode = false;
if (methodExists(instantTracker, instantTracker.onTrackingLost)) {
instantTracker.onTrackingLost();
}
this.setTrackingConfiguration(this.currentTrackingConfigPathOrIdentifier);
if (methodExists(this, this.onStopInstantTracking)) {
this.onStopInstantTracking();
}
};
scenario.skipTrackingInitialization = function () {
arel.Debug.log("scenario.skipTrackingInitialization()");
arel.Scene.sensorCommand("initialize", "", function(a) {});
if (methodExists(this, this.onSkipTrackingInitialization)) {
this.onSkipTrackingInitialization();
}
};
scenario.reloadTrackingConfiguration = function () {
arel.Debug.log("scenario.reloadTrackingConfiguration()");
this.setTrackingConfiguration(this.currentTrackingConfigPathOrIdentifier);
if (methodExists(this, this.onReloadTrackingConfiguration)) {
this.onReloadTrackingConfiguration();
}
};
scenario.setTrackingConfiguration = function (trackingConfigPathOrIdentifier) {
// Iterate over all trackables, simulate an onTrackingLost() for all those which are currently tracking.
var i, trackable;
for (i = 0; i < this.trackables.length; ++i) {
trackable = this.trackables[i];
if (trackable.isCurrentlyTracking && trackable != userDevice) {
if (methodExists(trackable, trackable.onTrackingLost)) {
trackable.onTrackingLost();
}
}
}
// Set the new tracking configuration.
arel.Scene.setTrackingConfiguration(trackingConfigPathOrIdentifier);
};
scenario.onStartup = function () {
arel.Debug.log("Welcome to the 'HouseProject' Augmented Reality experience.");
arel.Events.setListener(arel.Scene, scenario.sceneCallback, scenario);
if (google_analytics_id) {
arel.Debug.log("Google Analytics is enabled. Your account ID is: " + google_analytics_id);
arel.Debug.log("The event sampling rate is: arel.Plugin.Analytics.EventSampling.ONCE");
scenario.googleAnalytics = new arel.Plugin.Analytics(google_analytics_id, arel.Plugin.Analytics.EventSampling.ONCE, "");
} else {
arel.Debug.log("Note: No Google Analytics ID is set - Google Analytics will be disabled.");
}
if (methodExists(scenario, scenario.onLoaded)) {
scenario.onLoaded();
}
// The following contents have been defined in the index.xml file, therefore we need to register them
// and call their onLoaded() event manually.
scenario.registerObject(model6);
if (methodExists(model6, model6.onLoaded)) {
model6.onLoaded();
}
scenario.registerObject(model7);
if (methodExists(model7, model7.onLoaded)) {
model7.onLoaded();
}
if (methodExists(userDevice, userDevice.onLoaded)) {
userDevice.onLoaded();
}
// All objects have been defined, so start the AR experience by calling each trackable's .onLoaded() method.
var i, trackable;
for (i = 0; i < scenario.trackables.length; ++i) {
trackable = scenario.trackables[i];
if (methodExists(trackable, trackable.onLoaded)) {
trackable.onLoaded();
}
}
// Call the first scene's display() once to make sure that the content of that scene is initially visible.
scene1.display();
};
var scene1 = {};
scenario.scenes.push(scene1);
scene1.objectName = "scene1";
scene1.display = function () {
arel.Debug.log(this.objectName + ".display()");
if (scenario.currentScene == this) {
return;
}
// Iterate over all trackables, simulate an onTrackingLost() for all those which are currently tracking.
var trackingTrackables = [];
var i, trackable;
for (i = 0; i < scenario.trackables.length; ++i) {
trackable = scenario.trackables[i];
if (trackable.isCurrentlyTracking) {
// The instant tracker should be excluded from the tracking ones because it will be stopped later on.
if (trackable !== instantTracker) {
trackingTrackables.push(trackable);
}
if (methodExists(trackable, trackable.onTrackingLost)) {
trackable.onTrackingLost();
}
}
}
// In case any instant tracking is currently running, stop it before switching to the other scene.
scenario.stopInstantTracking();
var previousExperience360 = null;
if (scenario.currentExperience360) {
previousExperience360 = scenario.currentExperience360;
scenario.currentExperience360.hide();
}
scenario.currentScene = this;
// Iterate over all tracking trackables again, this time simulating an onDetected() and onTracked() event
// for all those which are currently tracking.
for (i = 0; i < trackingTrackables.length; ++i) {
trackable = trackingTrackables[i];
if (methodExists(trackable, trackable.onDetected)) {
trackable.onDetected();
}
if (methodExists(trackable, trackable.onTracked)) {
trackable.onTracked(trackable.currentTrackingValues);
}
}
if (previousExperience360) {
// A 360 was displayed in the previous scene, we now need to check whether any 360 in the new scene
// is triggered by the same trackable. If so, that 360 should be displayed.
var i, content;
for (i = 0; i < scenario.contents.length; ++i) {
content = scenario.contents[i];
if (content.type == "Experience360" && content.scene == this &&
content.associatedTrackable == previousExperience360.associatedTrackable) {
content.display();
break;
}
}
}
if (methodExists(this, this.onDisplayed)) {
this.onDisplayed();
}
};
var instantTracker = {};
scenario.trackables.push(instantTracker);
instantTracker.objectName = "instantTracker";
instantTracker.cosName = "InstantTracker";
instantTracker.cosID = "1";
instantTracker.isCurrentlyTracking = false;
instantTracker.currentTrackingValues = null;
instantTracker.onTracked = function (trackingValues) {
arel.Debug.log(this.objectName + ".onTracked()");
this.isCurrentlyTracking = true;
this.currentTrackingValues = trackingValues;
};
instantTracker.onTrackingLost = function (trackingValues) {
arel.Debug.log(this.objectName + ".onTrackingLost()");
this.isCurrentlyTracking = false;
this.currentTrackingValues = null;
};
var pattern2 = {};
scenario.trackables.push(pattern2);
pattern2.objectName = "pattern2";
pattern2.cosName = "Home1_1";
pattern2.cosID = "1";
pattern2.isCurrentlyTracking = false;
pattern2.currentTrackingValues = null;
pattern2.onTracked = function (trackingValues) {
arel.Debug.log(this.objectName + ".onTracked()");
this.isCurrentlyTracking = true;
this.currentTrackingValues = trackingValues;
// Try to call native from here
window.location = "js-call:" + "myObjectiveCFunction";
model6.display();
model6.play("Default Take", false);
};
pattern2.onTrackingLost = function (trackingValues) {
arel.Debug.log(this.objectName + ".onTrackingLost()");
this.isCurrentlyTracking = false;
this.currentTrackingValues = null;
model6.hide();
};
var pattern3 = {};
scenario.trackables.push(pattern3);
pattern3.objectName = "pattern3";
pattern3.cosName = "Home2_2";
pattern3.cosID = "2";
pattern3.isCurrentlyTracking = false;
pattern3.currentTrackingValues = null;
pattern3.onTracked = function (trackingValues) {
arel.Debug.log(this.objectName + ".onTracked()");
this.isCurrentlyTracking = true;
this.currentTrackingValues = trackingValues;
model7.display();
model7.play("Default Take", false);
};
pattern3.onTrackingLost = function (trackingValues) {
arel.Debug.log(this.objectName + ".onTrackingLost()");
this.isCurrentlyTracking = false;
this.currentTrackingValues = null;
model7.hide();
};
var userDevice = {};
userDevice.isCurrentlyTracking = true; // The pose of the user's device is always tracked...
scenario.trackables.push(userDevice);
userDevice.objectName = "userDevice";
userDevice.cosName = "Device";
userDevice.cosID = "-1";
userDevice.onTracked = function (trackingValues) {
arel.Debug.log(this.objectName + ".onTracked()");
this.isCurrentlyTracking = true;
this.currentTrackingValues = trackingValues;
};
userDevice.onTrackingLost = function (trackingValues) {
arel.Debug.log(this.objectName + ".onTrackingLost()");
this.isCurrentlyTracking = false;
this.currentTrackingValues = null;
};
// Kick-off the AR experience by calling the scenario's onStartup() method as soon as AREL is ready
scenario.onStartup();
});
On the iOS Side: UIWebview placed in a view controller and its delegate method to get Javascript call.
- (BOOL)webView:(UIWebView *)webView2
shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType {
NSLog(@"Inside WebView");
NSString *requestString = [[request URL] absoluteString];
if ([[[request URL] absoluteString] hasPrefix:@"js-call:"]) {
NSLog(@"Call from Javascript");
return NO;
}
// Accept this location change
return YES;
}
Here is the webview object created in header file:
#import "MetaioSDKViewController.h"
#import <metaioSDK/GestureHandlerIOS.h>
#import <metaioSDK/IARELInterpreterIOS.h>
// forward declarations
@class EAGLView;
@interface ARELViewController : MetaioSDKViewController<UIGestureRecognizerDelegate, IARELInterpreterIOSDelegate, UIWebViewDelegate>
{
metaio::IARELInterpreterIOS* m_ArelInterpreter;
GestureHandlerIOS* m_pGestureHandlerIOS;
NSString* m_arelFile;
}
@property (nonatomic, retain) IBOutlet UIWebView* m_arelWebView;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil instructions:(NSString *)arelTutorialConfig;
- (void) onSDKReady;
@end
And in .mm its set: (NOTE: Interface Builder also Delegate has been set )
- (void)viewDidLoad {
[super viewDidLoad];
m_arelWebView.delegate = self;
}
This is not at all getting called from Javascript when this functionality is executing.
Could someone advise me what could be the cause? Why the Javascript call is not triggering this native webview delegate.
Thank you!