Hi,
Did you already check the details on the Native <> JS communication:
With this sample and the respective documentation you should have a good starting point on how the Native <> JS communciation is working.
If you have further questions, it's also a good starting point to check other forum posts for further technical details.
Thx and greetings
Nicola
I see that Ar.platform.sendJSONObject() is sending data from javascript to native, method onJSONObjectReceived for receiving from javascript. I still get confuse
how to send data Poi From Java, not in javascript. Thanks
Did you check the forum for further details on the Native to JS communication:
https://support.wikitude.com/support/search/topics?term=Call+native+code+from+Javascript
Greetings
Nicola
Hi Nicola, thanks for the documentation. I get error when I use architectView.callJavascript().
public class MainActivity extends AppCompatActivity { private ArchitectView architectView; private String json; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate ( savedInstanceState ); setContentView ( R.layout.activity_main ); this.architectView = (ArchitectView) this.findViewById ( R.id.architectView ); final ArchitectStartupConfiguration config = new ArchitectStartupConfiguration (); config.setLicenseKey ( "kxVnyyNrfxwqXQhq45qR6dNCd/Edpcnmk27K8H3YMnHG6VtzhJZkT3NgCoONQEnBLN/UH/7LHwuBM9DsSKlet2n+Vs5RH4LFSL28Y/lDAWx0HOJSuwkISxrLA5auHNG3QqkgcYZvfECDZ3d4eap/ZEGZpcdqZY2Hv7AmVqk9vbVTYWx0ZWRfX0LOfmOLK0eM1UDkGGaiXC+6cW5gHTEOuvrhzr19fy0ezWXwgd1BIHLw4PVW2lL8Jv+emmNdizqUjLWcwCXqmI625QPm7UqG4sr1LwYnLDPpgkxdrqW2SMMWNHWsxCrryUGtm9+vYwLIIhC6AIBdJMvs0HW9wV2vjHzDWCloIZsstVvSj1lie+4gHjUW43IuNqEEHS1ELEWcNnZplT/x1KEQoq+6cZF+LceK2j0BXF/X461/ehY37bUq2PhNYsvCL2165K1TonXKp7JCVph3iZm7deNnUMFxRm1GyId4PPZVzwmfNrthVRw16P+Zeapah9SngD5vcms6CeFd0I0pW/nampjxwHJNjkktv06y9sAmI2TvUFHXCCTJole6fISBe5WNsyRsSQgcIaRaEERD/vCJ5/pmhlG/cohAA47pdHjkrctj3oSmVR2UziEYEcS/Zuc7voN+kuOKzu1pwvXd5qbXoW2BEhSvyTLJKzOsDJRoqKNbS1XtMqo=" ); this.architectView.onCreate ( config ); } @Override protected void onPostCreate(@Nullable Bundle savedInstanceState) { super.onPostCreate ( savedInstanceState ); this.architectView.onPostCreate (); FusedLocationProviderClient fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient ( this ); try { if (ActivityCompat.checkSelfPermission ( this, Manifest.permission.ACCESS_FINE_LOCATION ) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission ( this, Manifest.permission.ACCESS_COARSE_LOCATION ) != PackageManager.PERMISSION_GRANTED) { // TODO: Consider calling // ActivityCompat#requestPermissions // here to request the missing permissions, and then overriding // public void onRequestPermissionsResult(int requestCode, String[] permissions, // int[] grantResults) // to handle the case where the user grants the permission. See the documentation // for ActivityCompat#requestPermissions for more details. return; } fusedLocationProviderClient.getLastLocation ().addOnSuccessListener ( this, new OnSuccessListener<Location> () { @Override public void onSuccess(Location location) { architectView.setLocation ( location.getLatitude (), location.getLongitude (), location.getAltitude (), (float) 0.3 ); Log.d ( "Location", "Lat : " + location.getLatitude () + "Long : " + location.getLongitude () + "Alt : " + location.getAltitude () ); } } ); this.architectView.load( "08_Browsing_Pois_3_Limiting_Range/index.html"); json = "[{\"id\":\"1\"," + "\"longitude\":\"0.057\"," + "\"latitude\":\"0.095\"," + "\"description\":\"This is the description of POI#1\"," + "\"name\":\"POI#1\"}]"; architectView.callJavascript("World.getDataFromNative('"+json+"');"); } catch (IOException e) { e.printStackTrace (); } } @Override protected void onPause() { super.onPause (); this.architectView.onPause (); } @Override protected void onPostResume() { super.onPostResume (); this.architectView.onResume (); } @Override protected void onDestroy() { super.onDestroy (); this.architectView.onDestroy (); } }
and this is my JavaScript:
// information about server communication. This sample webservice is provided by Wikitude and returns random dummy places near given location var ServerInformation = { POIDATA_SERVER: "https://demo2164006.mockable.io/umkm", POIDATA_SERVER_ARG_LAT: "lat", POIDATA_SERVER_ARG_LON: "lon", POIDATA_SERVER_ARG_NR_POIS: "nrPois" }; // implementation of AR-Experience (aka "World") var World = { // user's latest known location, accessible via userLocation.latitude, userLocation.longitude, userLocation.altitude 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 markerDrawable_idle: null, markerDrawable_selected: null, markerDrawable_directionIndicator: 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) { // show radar & set click-listener PoiRadar.show(); $('#radarContainer').unbind('click'); $("#radarContainer").click(PoiRadar.clickedRadar); // empty list of visible markers World.markerList = []; // start loading marker assets World.markerDrawable_idle = new AR.ImageResource("assets/marker_idle.png"); World.markerDrawable_selected = new AR.ImageResource("assets/marker_selected.png"); World.markerDrawable_directionIndicator = new AR.ImageResource("assets/indi.png"); // 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.updateDistanceToUserValues(); World.updateStatusMessage(currentPlaceNr + ' places loaded'); // set distance slider to 100% $("#panel-distance-range").val(100); $("#panel-distance-range").slider("refresh"); }, // 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) { var themeToUse = isWarning ? "e" : "c"; var iconToUse = isWarning ? "alert" : "info"; $("#status-message").html(message); $("#popupInfoButton").buttonMarkup({ theme: themeToUse }); $("#popupInfoButton").buttonMarkup({ icon: iconToUse }); }, // 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 World.updateDistanceToUserValues(); } // helper used to update placemark information every now and then (e.g. every 10 location upadtes fired) World.locationUpdateCounter = (++World.locationUpdateCounter % World.updatePlacemarkDistancesEveryXLocationUpdates); }, // fired when user pressed maker in cam onMarkerSelected: function onMarkerSelectedFn(marker) { World.currentMarker = marker; // update panel values $("#poi-detail-title").html(marker.poiData.title); $("#poi-detail-description").html(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 recalcualte this specific distance before we update the UI. */ if( undefined == marker.distanceToUser ) { marker.distanceToUser = marker.markerObject.locations[0].distanceToUser(); } var distanceToUserValue = (marker.distanceToUser > 999) ? ((marker.distanceToUser / 1000).toFixed(2) + " km") : (Math.round(marker.distanceToUser) + " m"); $("#poi-detail-distance").html(distanceToUserValue); // show panel $("#panel-poidetail").panel("open", 123); $( ".ui-panel-dismiss" ).unbind("mousedown"); $("#panel-poidetail").on("panelbeforeclose", function(event, ui) { World.currentMarker.setDeselected(World.currentMarker); }); }, // 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 World.markerList.sort(World.sortByDistanceSortingDescending); // 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; }, // udpates values show in "range panel" updateRangeValues: function updateRangeValuesFn() { // get current slider value (0..100); var slider_value = $("#panel-distance-range").val(); // 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 $("#panel-distance-value").html(maxRangeValue); $("#panel-distance-places").html((placesInRange != 1) ? (placesInRange + " Places") : (placesInRange + " Place")); // 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 World.markerList.sort(World.sortByDistanceSorting); // 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() { $("#panel-distance").on("panelclose", function(event, ui) { $("#radarContainer").addClass("radarContainer_left"); $("#radarContainer").removeClass("radarContainer_right"); PoiRadar.updatePosition(); }); $("#panel-distance").on("panelopen", function(event, ui) { $("#radarContainer").removeClass("radarContainer_left"); $("#radarContainer").addClass("radarContainer_right"); PoiRadar.updatePosition(); }); }, // display range slider showRange: function showRangeFn() { if (World.markerList.length > 0) { // update labels on every range movement $('#panel-distance-range').change(function() { World.updateRangeValues(); }); World.updateRangeValues(); World.handlePanelMovements(); // open panel $("#panel-distance").trigger("updatelayout"); $("#panel-distance").panel("open", 1234); } else { // no places are visible, because the are not loaded yet World.updateStatusMessage('No places available yet', true); } }, // request POI data /*requestDataFromServer: function requestDataFromServerFn(lat, lon) { // set helper var to avoid requesting places while loading //World.isRequestingData = true; // actual is true up 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 + "=10"; var jqxhr = $.getJSON(serverUrl, function(data) { World.loadPoisFromJsonData(data); }) .error(function(err) { World.updateStatusMessage("Invalid web-service response.", true); World.isRequestingData = false; }) .complete(function() { World.isRequestingData = false; }); },*/ getDataFromNative: function getDataFromNativeFn(data){ var url = data; World.loadPoisFromJsonData(data); }, // helper to sort places by distance sortByDistanceSorting: function(a, b) { return a.distanceToUser - b.distanceToUser; }, // helper to sort places by distance, descending sortByDistanceSortingDescending: function(a, b) { return b.distanceToUser - a.distanceToUser; } }; /* forward locationChanges to custom function */ AR.context.onLocationChanged = World.locationChanged; /* forward clicks in empty area to World */ AR.context.onScreenClick = World.onScreenClick;
My error log is: E/ArchitectView: setLocation: LocationService is not initialized. When I remove architectView.callJavascript. The error has gone.
thanks
Ali Taufiqfajar
Hi there, How could I pass poi data from java(Android Studio) to marker.js ? I find this doc
http://www.wikitude.com/external/doc/documentation/6.1/android/retrievingpoidata.html#local
Those only in javascript, not in java.
Because i have got data from web api using java, my search in java is dynamic.
Thanks