OGC WMTS layer example for Android?

4969
7
Jump to solution
06-29-2016 10:50 PM
TeroRönkkö
Occasional Contributor


Does anyone have experience working against OGC WMTS services with Android Runtime SDK? Do you have example somewhere you could share? I am having trouble understanding how to go on with these as they don't seem to work as the other layer types.

T

0 Kudos
1 Solution

Accepted Solutions
ShellyGill1
Esri Contributor

Hi Tero,

I had a look at your WMTS endpoint and it looks like it only supports KVP mode, not REST. The default mode for the WMTSLayer in the Esri Android SDK is REST mode, so I think the requests being sent to the service are asking for the layer in REST mode. You can explicitly set the mode if you use WMTSLayerInfo:

  WMTSServiceInfo wmtsServiceInfo = WMTSServiceInfo.fetch("https://julkinen.liikennevirasto.fi/rasteripalvelu/wmts",

   null, WMTSServiceMode.KVP);

(As you found, fetch does not switch to a background thread to do network requests like the layer constructors do, so do this on a background thread yourself). You can iterate all the WMTSLayerInfo items in the service this way.

Theres no constructor on WMTSLayer that allows you to set the KVP mode, and the layer starts to initialize by default, so you can't change the mode after that. However, there is a constructor where you can say not to immediately initialize the layer, as below - then set the mode to KVP, and then initialize the layer and add it to the mapView after that:

  WMTSLayer layer = new WMTSLayer("https://julkinen.liikennevirasto.fi/rasteripalvelu/wmts", null, false);

  layer.setServiceMode(WMTSServiceMode.KVP);

  layer.layerInitialise();

Using this code I could see the WMTSLayer in the MapView. I added this to a blank map, as I think perhaps that service doesnt support web mercator (from a quick browse of the capabilities), so I'm assuming here you're adding this to a map where the basemap SpatialReference matches those supported by the WMTS service.

Hope this helps,

Shelly

View solution in original post

7 Replies
AlexanderNohe1
Occasional Contributor III

Have you already taken a look at the following documentation:

WMTSLayer | ArcGIS Android 10.2.8 API

Additionally, this is the syntax from that documentation on how to initialize that type of layer:

WMTSServiceInfo serviceInfo = WMTSServiceInfo.fetch("http://[SERVER:PORT]/[INSTANCE]/services/[SERVICE]/MapServer/WMTS/1.0.0/WMTSCapabilities.xml");
 WMTSLayerInfo layerInfo = serviceInfo.getLayerInfos().get(0);
 WMTSLayer layer = new WMTSLayer(layerInfo, SpatialReference.create(3857));
 layer.layerInitialise();

Are you able to share the WMTS file that you are experiencing trouble with?

0 Kudos
TeroRönkkö
Occasional Contributor

Hi,

this is the source for the wmts:

https://julkinen.liikennevirasto.fi/rasteripalvelu/wmts?request=getcapabilities

I tried that example (will try again and report results) but if I understand correctly I run in to networkonmainthreadexception which basically means that I would need to do that fetch somehow on another thread?

With other layer types just adding it to the map seems to be enough.

0 Kudos
AlexanderNohe1
Occasional Contributor III

Using the topo basemap I was able to get this to work via the following Activity:

package com.arcgis.androidsupportcases.ogcwmts;

import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import com.esri.android.map.MapView;
import com.esri.android.map.event.OnStatusChangedListener;
import com.esri.android.map.ogc.WMTSLayer;
import com.esri.core.geometry.SpatialReference;
import com.esri.core.ogc.wmts.WMTSLayerInfo;
import com.esri.core.ogc.wmts.WMTSServiceInfo;

public class MainActivity extends AppCompatActivity {

  MapView mapView;

  @Override protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_main);

   mapView = (MapView) findViewById(R.id.map);
   mapView.setOnStatusChangedListener(new OnStatusChangedListener() {
   @Override public void onStatusChanged(Object o, STATUS status) {
   if (status == STATUS.INITIALIZED) {
  AsyncTask.execute(new Runnable() {
   @Override public void run() {
  WMTSServiceInfo serviceInfo = null;
  try {
  serviceInfo =
  WMTSServiceInfo.fetch("http://server.arcgisonline.com/arcgis/rest/services/World_Topo_Map/MapServer/WMTS/1.0.0/WMTSCapabili...");
   WMTSLayerInfo layerInfo = serviceInfo.getLayerInfos().get(0);
  final WMTSLayer layer = new WMTSLayer(layerInfo, SpatialReference.create(3857));
   layer.layerInitialise();
   layer.setOnStatusChangedListener(new OnStatusChangedListener() {
   @Override public void onStatusChanged(Object o, STATUS status) {
   if(status == STATUS.INITIALIZED) {
   mapView.addLayer(layer);
   }
  }
  });
   } catch (Exception e) {
  e.printStackTrace();
   }
  }
  });
   }
  }
  });


  }
}
TeroRönkkö
Occasional Contributor

Thanks for the example! Anyhow I still can't open the wmts service I provided with the same code. The service in ther e works in Arcmap so it should be ok.

It gives EsriServiceException "Bad request" on fetch - with your link it works. Do you have any hints how to continue and what could be wrong?

Tero

0 Kudos
TeroRönkkö
Occasional Contributor

Update:

It actually seems like there is a "bug" in the implementation of the wmtsserviceinfo fetch functionality: the wmts service I want to fetch is some kind of dynamic web service and not static xml file. If I download the output (which is xml) with wget i get the xml (with "wrong" name though) and if I copy it as xml file to another web server and use that in wmtsserviceinfo, it works fine.

Except of course that I can't make it show anything, but it goes forward from the bad request.

the same output as file in my own website: http://www.ronkko.fi/capa.xml

I will report this via the official esri channel as a bug unless I get some tips here how to circumvent this. Perhaps it gets fixed eventually. Unfortunately for me I can't continue before the fix as I don't have way to have effect in the wmts server owner.

0 Kudos
ShellyGill1
Esri Contributor

Hi Tero,

I had a look at your WMTS endpoint and it looks like it only supports KVP mode, not REST. The default mode for the WMTSLayer in the Esri Android SDK is REST mode, so I think the requests being sent to the service are asking for the layer in REST mode. You can explicitly set the mode if you use WMTSLayerInfo:

  WMTSServiceInfo wmtsServiceInfo = WMTSServiceInfo.fetch("https://julkinen.liikennevirasto.fi/rasteripalvelu/wmts",

   null, WMTSServiceMode.KVP);

(As you found, fetch does not switch to a background thread to do network requests like the layer constructors do, so do this on a background thread yourself). You can iterate all the WMTSLayerInfo items in the service this way.

Theres no constructor on WMTSLayer that allows you to set the KVP mode, and the layer starts to initialize by default, so you can't change the mode after that. However, there is a constructor where you can say not to immediately initialize the layer, as below - then set the mode to KVP, and then initialize the layer and add it to the mapView after that:

  WMTSLayer layer = new WMTSLayer("https://julkinen.liikennevirasto.fi/rasteripalvelu/wmts", null, false);

  layer.setServiceMode(WMTSServiceMode.KVP);

  layer.layerInitialise();

Using this code I could see the WMTSLayer in the MapView. I added this to a blank map, as I think perhaps that service doesnt support web mercator (from a quick browse of the capabilities), so I'm assuming here you're adding this to a map where the basemap SpatialReference matches those supported by the WMTS service.

Hope this helps,

Shelly

PhilScovis
New Contributor III

I am having a similar problem in .NET runtime version 100.1. For example, using the endpoint:

http://opencache.statkart.no/gatekeeper/gk/gk.open_wmts?Version=1.0.0&service=wmts&request=getcapabi...

In 100.1 I cannot find similar API calls to the solutions here. In particular, there doesn't seem to be any way to set the service mode of the layer to KVP.

 WmtsService service = new WmtsService(_TiledUri);
 await service.LoadAsync();
 WmtsServiceInfo info = service.ServiceInfo;
 _TiledLayer = new WmtsLayer(info.LayerInfos.ToArray()[0]);
 _MapView.Map.Basemap.BaseLayers.Add(_TiledLayer);
 _TiledLayer.IsVisible = true;
 await _TiledLayer.LoadAsync();

How is KVP service mode specified in 100.1?