Start a new topic

SDK 9.5.0 error sample example for Cordova

Hello dear friends of Wikitude. I'd like to request your help.

I update my Pro 3D license. And when installing the new version 9.5.0 of Wikitude. I have 2 problems that I cannot solve alone:

1) The first problem: I cannot give different images to my POIS. Only be able to always place the same one. I want 1 POI to be green, another POI red and another POI yellow. But not being able to do it. Please help me achieve this.

2) The second problem: updating my version of Wikitude. I can compile my application, but the AR view button won't open. In Android Studio it throws the following error:

[INFO:CONSOLE(56)] "Uncaught TypeError: Cannot read property 'applicationDirectory' of undefined", source: file:///android_asset/www/js/wikitude/index.js (56)

This is happening with the sample application. I check the Wikitude forum and other forums on the internet, but I can't solve my problems.

The Detail of my project:

1) Wikitude SDK version: Wikitude SDK 9.5.0
2) Working SDK: Cordova
3) Platform version: Cordova 10.0.0, Android Studio 4.1.1
4) Test device: Samsung Galaxy A70, Android 10.

I hope your help. Thanks a lot.


For the first issue you have, you have to control it in the html/css/js side. If you take a look at the POI samples inside our sample application, such as the 08_PointOfInterest_3_MultiplePois, you will see that our markers can have 2 different backgrounds, one idle and one when the marker is selected. This is controlled in the multiplepois.js and the marker.js files and it is basically changing the png's that are drawn. If you want to change the color of a POI to be green, it has to be done the same way that those 2 files -> you create an AR.ImageResource setting the image you want and create an AR.ImageDrawable with the ImageResource you created before as parameter.

Unfortunately I could not reproduce your second issue: I did download our sample app from scratch from, followed the steps and everything was working fine. Could you tell me what steps did you follow so I can try to reproduce it from my side?




the step by step of my work according to the documentation

1. create new cordova project according to wikitude documentation

2. add the platform (iOS - Android) to the project

3. add sdk wikitude to the project by installing the wikitude cordova plugin

4. I download sample examples from

5. unzip the .zip

6. I add the samples manually and replace all the files in the folders: www / css, www / js, index.html and fully install www / jquery, www / world

7. I rebuild the project

8. I integrate the key

9. then I go to android studio and import my android project (android platform app folder)

10. I connect my smartphone and run the app on my device

11. Immediately the app opens and I see the menu with all the wikitude sample examples. But when each button is touched, the app does not open the camera view, that is, it does not open the AR worlds of each example created by you.

I must say that I have already done this in previous years and never had this problem. I know your sdk since 2013. I hope you can help me. thank you very much


I did follow your steps and I could reproduce and fix your issue. The problem here is that you are missing the cordova-plugin-file ->

The samples zip you can download from: will work fine if you follow the documentation that is written in that page, where you have to call an .sh file that will create the cordova project itself and download all the required plugin to make the www folder to work properly. If you just take the www folder as it is, the error you are having is expected.



Hello dear friends, sorry for the delay in responding.

Following your instructions and downloading from your links, I was able to solve problem number 2. This error:

[INFO: CONSOLE (56)] "Uncaught TypeError: Cannot read property 'applicationDirectory' of undefined", source: file: ///android_asset/www/js/wikitude/index.js (56)

It disappeared and I was able to compile my work! So thank you very much, you are a genius !!!

I suggest that you update your documentation, because all the steps that I previously followed, including downloading from github, were in the official documentation.

-------------------------------------------------- -----------------------------------------------

I am currently trying to solve problem number 1:

"I cannot give different images to my POIS. Only be able to always place the same one. I want 1 POI to be green, another POI red and another POI yellow. But not being able to do it. Please help me achieve this"

I cannot make each POI have a different image. In its showcase the following Apps develop it:





How do you think it is possible to develop this programming?

- I try to use the example of multiple POIs assigning each POI an imageDrawable using JSON, but it throws an error

- I try to integrate the example of the solar system. But the programming is of limited elements and they are not generated automatically through a class.

What am I doing wrong?

A hug

So each POI is an instance of an AR.GeoObject which includes some drawables as you can see in the marker.js file from the 08_PointOfInterest_3_MultiplePois sample. If you take a look at that sample, the first drawable is an instance of an AR.ImageDrawable which takes a png as parameter. In our case the png is always blue, but that doesn't stop you to do as you please and create different AR.ImageDrawables for different AR.GeoObjects.

For your purpose, just to test, I would suggest you to create some AR.ImageDrawables with different png's on each one of them, and assign them on different AR.GeoObjects created in the same way we do in the marker.js file.



Hi Aitor,

follow your advice and also look in the forum and find this answer:, integrate the code with the example 10_BrowsingPois_4_ReloadingContent, but I can't see the POIs. They are not displayed in AR view. Can you help me integrate this solution to achieve different POIs according to categories?

Thanks, Romina

my try : archive reloadingcontent.js


    Information about server communication. This sample webservice is provided by Wikitude and returns random dummy
    places near given location.
var ServerInformation = {

/* Implementation of AR-Experience (aka "World"). */
var World = {

        User's latest known location, accessible via userLocation.latitude, userLocation.longitude,
    userLocation: null,

    /* You may request new data from server periodically, however: in this sample data is only requested once. */
    isRequestingData: false,

    /* True once data was fetched. */
    initiallyLoadedData: false,

    /* Different POI-Marker assets. */
    markerDrawableIdle: null,
    markerDrawableSelected: null,
    markerDrawableDirectionIndicator: null,

    /* List of AR.GeoObjects that are currently shown in the scene / World. */
    markerList: [],

    /* the last selected marker. */
    currentMarker: null,

    locationUpdateCounter: 0,
    updatePlacemarkDistancesEveryXLocationUpdates: 10,

    /* Called to inject new POI data. */
    loadPoisFromJsonData: function loadPoisFromJsonDataFn(poiData) {

        /* Destroys all existing AR-Objects (markers & radar). */

        /* Show radar. */;

        /* Empty list of visible markers. */
        World.markerList = [];

        /* Start loading marker assets. */
        World.markerDrawableIdle = new AR.ImageResource("assets/marker_idle.png", {
            onError: World.onError
        World.markerDrawableSelected = new AR.ImageResource("assets/marker_selected.png", {
            onError: World.onError
        World.markerDrawableDirectionIndicator = new AR.ImageResource("assets/indi.png", {
            onError: World.onError

/* intento disferentes poi */

World.markerDrawableIdle = {"idle": {}, "selected": {}};
World.markerDrawableIdle.idle["typeA"] = new AR.ImageResource("assets/typeA_idle.png")
World.markerDrawableIdle.selected["typeA"] = new AR.ImageResource("assets/typeA_idle.png")
World.markerDrawableIdle.idle["typeB"] = new AR.ImageResource("assets/typeB_idle.png")
World.markerDrawableIdle.selected["typeB"] = new AR.ImageResource("assets/typeB_idle.png")

/* fin intento disferentes poi */

/* Create an AR.ImageDrawable for the marker in idle state. */
      this.markerDrawableIdle = new AR.ImageDrawable(World.markerDrawableIdle, 2.5, {
        zOrder: 0,
        opacity: 1.0,
            To react on user interaction, an onClick property can be set for each AR.Drawable. The property is a
            function which will be called each time the user taps on the drawable. The function called on each tap
            is returned from the following helper function defined in marker.js. The function returns a function
            which checks the selected state with the help of the variable isSelected and executes the appropriate
            function. The clicked marker is passed as an argument.
        onClick: Marker.prototype.getOnClickTrigger(this)

    /* Create an AR.ImageDrawable for the marker in selected state. */
    this.markerDrawableSelected = new AR.ImageDrawable(World.markerDrawableSelected, 2.5, {
        zOrder: 0,
        opacity: 0.0,
        onClick: null

        /* Loop through POI-information and create an AR.GeoObject (=Marker) per POI. */
        for (var currentPlaceNr = 0; currentPlaceNr < poiData.length; currentPlaceNr++) {
            var singlePoi = {
                "id": poiData[currentPlaceNr].id,
                "latitude": parseFloat(poiData[currentPlaceNr].latitude),
                "longitude": parseFloat(poiData[currentPlaceNr].longitude),
                "altitude": parseFloat(poiData[currentPlaceNr].altitude),
                "title": poiData[currentPlaceNr].name,
                "description": poiData[currentPlaceNr].description

            World.markerList.push(new Marker(singlePoi));

        /* Updates distance information of all placemarks. */

        World.updateStatusMessage(currentPlaceNr + ' places loaded');

        /* Set distance slider to 100%. */
        document.getElementById("panelRangeSliderValue").innerHTML = 100;

        Sets/updates distances of all makers so they are available way faster than calling (time-consuming)
        distanceToUser() method all the time.
    updateDistanceToUserValues: function updateDistanceToUserValuesFn() {
        for (var i = 0; i < World.markerList.length; i++) {
            World.markerList[i].distanceToUser = World.markerList[i].markerObject.locations[0].distanceToUser();

    /* Updates status message shown in small "i"-button aligned bottom center. */
    updateStatusMessage: function updateStatusMessageFn(message, isWarning) {
        document.getElementById("popupButtonImage").src = isWarning ? "assets/warning_icon.png" : "assets/info_icon.png";
        document.getElementById("popupButtonTooltip").innerHTML = message;

    /* Location updates, fired every time you call architectView.setLocation() in native environment. */
    locationChanged: function locationChangedFn(lat, lon, alt, acc) {

        /* Store user's current location in World.userLocation, so you always know where user is. */
        World.userLocation = {
            'latitude': lat,
            'longitude': lon,
            'altitude': alt,
            'accuracy': acc

        /* Request data if not already present. */
        if (!World.initiallyLoadedData) {
            World.requestDataFromServer(lat, lon);
            World.initiallyLoadedData = true;
        } else if (World.locationUpdateCounter === 0) {
                Update placemark distance information frequently, you max also update distances only every 10m with
                some more effort.

        /* Helper used to update placemark information every now and then (e.g. every 10 location upadtes fired). */
        World.locationUpdateCounter =
            (++World.locationUpdateCounter % World.updatePlacemarkDistancesEveryXLocationUpdates);

        POIs usually have a name and sometimes a quite long description.
        Depending on your content type you may e.g. display a marker with its name and cropped description but
        allow the user to get more information after selecting it.

    /* Fired when user pressed maker in cam. */
    onMarkerSelected: function onMarkerSelectedFn(marker) {

        World.currentMarker = marker;

            In this sample a POI detail panel appears when pressing a cam-marker (the blue box with title &
            description), compare index.html in the sample's directory.
        /* Update panel values. */
        document.getElementById("poiDetailTitle").innerHTML = marker.poiData.title;
        document.getElementById("poiDetailDescription").innerHTML = marker.poiData.description;

            It's ok for AR.Location subclass objects to return a distance of `undefined`. In case such a distance
            was calculated when all distances were queried in `updateDistanceToUserValues`, we recalculate this
            specific distance before we update the UI.
        if (undefined === marker.distanceToUser) {
            marker.distanceToUser = marker.markerObject.locations[0].distanceToUser();

            Distance and altitude are measured in meters by the SDK. You may convert them to miles / feet if
        var distanceToUserValue = (marker.distanceToUser > 999) ?
            ((marker.distanceToUser / 1000).toFixed(2) + " km") :
            (Math.round(marker.distanceToUser) + " m");

        document.getElementById("poiDetailDistance").innerHTML = distanceToUserValue;

        /* Show panel. */
        document.getElementById("panelPoiDetail").style.visibility = "visible";

    closePanel: function closePanel() {
        /* Hide panels. */
        document.getElementById("panelPoiDetail").style.visibility = "hidden";
        document.getElementById("panelRange").style.visibility = "hidden";

        if (World.currentMarker != null) {
            /* Deselect AR-marker when user exits detail screen div. */
            World.currentMarker = null;

    /* Screen was clicked but no geo-object was hit. */
    onScreenClick: function onScreenClickFn() {
        /* You may handle clicks on empty AR space too. */

    /* Returns distance in meters of placemark with maxdistance * 1.1. */
    getMaxDistance: function getMaxDistanceFn() {

        /* Sort places by distance so the first entry is the one with the maximum distance. */

        /* Use distanceToUser to get max-distance. */
        var maxDistanceMeters = World.markerList[0].distanceToUser;

            Return maximum distance times some factor >1.0 so ther is some room left and small movements of user
            don't cause places far away to disappear.
        return maxDistanceMeters * 1.1;

    /* Updates values show in "range panel". */
    updateRangeValues: function updateRangeValuesFn() {

        /* Get current slider value (0..100);. */
        var slider_value = document.getElementById("panelRangeSlider").value;
        /* Max range relative to the maximum distance of all visible places. */
        var maxRangeMeters = Math.round(World.getMaxDistance() * (slider_value / 100));

        /* Range in meters including metric m/km. */
        var maxRangeValue = (maxRangeMeters > 999) ?
            ((maxRangeMeters / 1000).toFixed(2) + " km") :
            (Math.round(maxRangeMeters) + " m");

        /* Number of places within max-range. */
        var placesInRange = World.getNumberOfVisiblePlacesInRange(maxRangeMeters);

        /* Update UI labels accordingly. */
        document.getElementById("panelRangeValue").innerHTML = maxRangeValue;
        document.getElementById("panelRangePlaces").innerHTML = (placesInRange != 1) ?
            (placesInRange + " Places") : (placesInRange + " Place");
        document.getElementById("panelRangeSliderValue").innerHTML = slider_value;

        World.updateStatusMessage((placesInRange != 1) ?
            (placesInRange + " places loaded") : (placesInRange + " place loaded"));

        /* Update culling distance, so only places within given range are rendered. */
        AR.context.scene.cullingDistance = Math.max(maxRangeMeters, 1);

        /* Update radar's maxDistance so radius of radar is updated too. */
        PoiRadar.setMaxDistance(Math.max(maxRangeMeters, 1));

    /* Returns number of places with same or lower distance than given range. */
    getNumberOfVisiblePlacesInRange: function getNumberOfVisiblePlacesInRangeFn(maxRangeMeters) {

        /* Sort markers by distance. */

        /* Loop through list and stop once a placemark is out of range ( -> very basic implementation ). */
        for (var i = 0; i < World.markerList.length; i++) {
            if (World.markerList[i].distanceToUser > maxRangeMeters) {
                return i;

        /* In case no placemark is out of range -> all are visible. */
        return World.markerList.length;

    handlePanelMovements: function handlePanelMovementsFn() {

    /* Display range slider. */
    showRange: function showRangeFn() {
        if (World.markerList.length > 0) {

            /* Update labels on every range movement. */

            /* Open panel. */
            document.getElementById("panelRange").style.visibility = "visible";
        } else {

            /* No places are visible, because the are not loaded yet. */
            World.updateStatusMessage('No places available yet', true);

        You may need to reload POI information because of user movements or manually for various reasons.
        In this example POIs are reloaded when user presses the refresh button.
        The button is defined in index.html and calls World.reloadPlaces() on click.

    /* Reload places from content source. */
    reloadPlaces: function reloadPlacesFn() {
        if (World.markerList.length > 0) {
        if (!World.isRequestingData) {
            if (World.userLocation) {
                World.requestDataFromServer(World.userLocation.latitude, World.userLocation.longitude);
            } else {
                World.updateStatusMessage('Unknown user-location.', true);
        } else {
            World.updateStatusMessage('Already requesing places...', true);

    /* Request POI data. */
    requestDataFromServer: function requestDataFromServerFn(lat, lon) {

        /* Set helper var to avoid requesting places while loading. */
        World.isRequestingData = true;
        World.updateStatusMessage('Requesting places from web-service');

        /* Server-url to JSON content provider. */
        var serverUrl = ServerInformation.POIDATA_SERVER + "?" + ServerInformation.POIDATA_SERVER_ARG_LAT + "=" +
            lat + "&" + ServerInformation.POIDATA_SERVER_ARG_LON + "=" +
            lon + "&" + ServerInformation.POIDATA_SERVER_ARG_NR_POIS + "=20";

        /* Use GET request to fetch the JSON data from the server */
        var xhr = new XMLHttpRequest();'GET', serverUrl, true);
        xhr.responseType = 'json';
        xhr.onload = function() {
            var status = xhr.status;
            if (status === 200) {
                World.isRequestingData = false;
            } else {
                World.updateStatusMessage("Invalid web-service response.", true);
                World.isRequestingData = false;

    /* Helper to sort places by distance. */
    sortByDistanceSorting: function sortByDistanceSortingFn(a, b) {
        return a.distanceToUser - b.distanceToUser;

    /* Helper to sort places by distance, descending. */
    sortByDistanceSortingDescending: function sortByDistanceSortingDescendingFn(a, b) {
        return b.distanceToUser - a.distanceToUser;

    onError: function onErrorFn(error) {

/* Forward locationChanges to custom function. */
AR.context.onLocationChanged = World.locationChanged;

/* Forward clicks in empty area to World. */
AR.context.onScreenClick = World.onScreenClick;


Dear Rom,

I see that this thread covers a lot of instructions and details provided by Aitor and I’d like to add details to our support process in general to manage your expectations. For questions such as the one we’re dealing in this thread, our approach is to give instructions and ideas on how to solve the problem, links to the Wikitude documentation and samples. We’re not providing 3rd party development and therefore can't implement any code or samples. As the support is done by our core team to ensure a high quality support process, I hope you can understand that we need to work efficiently.
Ideally you make sure that you fully understand the sample app, and start by testing if your POIs are visible in the SDK sample app and from there.

Again we want to thank you for your understanding.

Thx and greetings


Hello nicola, thanks for your answer, the truth is I asked for that code because I saw that the support oriented who made the question.

For my part, I will continue testing to see if I get what he proposed.

thanks Aitor for your help.


Login or Signup to post a comment