Select to view content in your preferred language

Export Tiles from built-in basemap in ArcGIS Runtime

2814
27
Jump to solution
09-19-2017 10:10 AM
NicholasLiccini
Emerging Contributor

Hi!

I would like to save a predefined area of interest of a MapView that can be loaded when there is no network connection. I tried following the ArcGIS Samples for "ExportTiles" but it keeps failing. I am not sure what the correct solution would be, but perhaps someone could provide the steps I should follow to export the map tiles.

Thank you!

Nick

0 Kudos
27 Replies
LukeSmallwood
Esri Contributor

You would need to register it (probably in your main.cpp) for QML - something like this:

qmlRegisterUncreatableType<AuthenticationManager>("Esri.MyApp", 1, 0, "AuthenticationManager", "AuthenticationManager is uncreateable");
0 Kudos
NicholasLiccini
Emerging Contributor

Yes I have done this. Maybe I am defining the AuthenticationView incorrectly in the QML?

My setup is structured similar to this:

MyApp {
    id: myapp
    // other properties
   
    AuthenticationView {
        anchors.fill: parent
        authenticationManager: myapp.authManager
    }
    // Other QML Items (MapView, Rectangles, etc)
}

0 Kudos
NicholasLiccini
Emerging Contributor

Where authManager is the READ function of a Q_PROPERTY defined in my myapp.cpp file to return AuthenticationManager::instance()

0 Kudos
LukeSmallwood
Esri Contributor

Its hard to tell without seeing all of the code - but it looks to me as though the property has not notified QML that the authManager is ready yet. Do you have a signal that you emit in the c'tor of your type to show that the property (the singleton) has changed? Or is the property marked CONSTANT?

0 Kudos
NicholasLiccini
Emerging Contributor

The property is marked as CONSTANT like how the sample does it. Do I need to connect a signal in the QML for when the singleton has changed?

0 Kudos
LukeSmallwood
Esri Contributor

You shouldn't need to I don't think. Maybe you can try printing console.log(myApp.authManager) when the apps Component.onComplete event occurs to see what it displays? 

0 Kudos
NicholasLiccini
Emerging Contributor

Luke,

So it seems that I am able to catch the AuthenticationChallenge with the code below (which in my case is consistently the need for a username/password), but when I provide credentials (my username/password for my ArcGIS Developer account) I receive an error saying "unable to generate token". I am trying to get access to the portal "https://tiledbasemaps.arcgis.com" (the group of basemaps for export that you provided), but am consistently unable to get access.

My underlying need is to be able to press a button on the UI that will call a method to export the current view of the map to a .tpk file which can then be loaded another time. I believe the tiledbasemaps group has the right data for this, but I can't seem to figure out how to provide the right credentials to access them. My thought is to create a Portal linked to my developer account and to log in that way so that the map already has the correct credentials, but this doesn't seem to be working.

Any advice for a different approach or how to generate a valid token from within the Runtime?

Thank you,

Nick

0 Kudos
NicholasLiccini
Emerging Contributor
I have a setup within the myapp.cpp file to identify and handle the different types of challenges without the QML view (this block was made following the topic article you mentioned above). But it refuses to accept my login credentials and gives an error message saying "Token required"
Any thoughts why that would be happening?

QMetaObject::Connection connection = connect(AuthenticationManager::instance(), &AuthenticationManager::authenticationChallenge, this, [this](AuthenticationChallenge* challenge){
        switch(challenge->authenticationChallengeType()){
            case AuthenticationChallengeType::UsernamePassword:
                challenge->continueWithUsernamePassword(userName, password);
                std::cout << "Needs username and password" << std::endl;
                break;
            case AuthenticationChallengeType::OAuth:
                // continueWithOAuthAuthorizationCode
                std::cout << "Needs OAuth" << std::endl;
                break;
            case AuthenticationChallengeType::ClientCertificate:
                // continueWithClientCertificate
                std::cout << "Needs client certificate" << std::endl;
                break;
            case AuthenticationChallengeType::SslHandshake:
                // continueWithSslHandshake
                std::cout << "Needs SSL handshake" << std::endl;
                break;
            case AuthenticationChallengeType::Unknown:
                std::cout << "Unknown challenge" << std::endl;
                break;
        }
    });

The cause of the AuthenticationChallenge I believe is this:

QUrl serviceUrl_ = QUrl("https://tiledbasemaps.arcgis.com/arcgis/rest/services/World_Imagery/MapServer");

p_ExportTask_ = new ExportTileCacheTask(serviceUrl_, this);
connect(p_ExportTask_, &ExportTileCacheTask::doneLoading, this, [this](Error error){
        if(!error.isEmpty()){
            std::cout << "Load error: " << error.message().toStdString() << std::endl;
        }
});
p_ExportTask_->load();
0 Kudos
LukeSmallwood
Esri Contributor

Hi Nicholas - I think there may be an issue with logging in using the workflow you describe (I will log an issue to look into that). Here is some workaround code that will first authenticates using a portal - this works for me, so hopefully it should solve your problem.

void ExportTiles::componentComplete()
{
  QQuickItem::componentComplete();
  // create Portal and load
  Portal* portal = new Portal(QUrl("https://arcgis.com"), true, this);
  connect(portal, &Portal::doneLoading, this, [this](Error e)
  {
    if (!e.isEmpty())
      qDebug() << e.message() << e.additionalMessage();
    else
      qDebug() << "portal loaded";
  });
  //portal->load(); // this will trigger an authentication challenge for AGOL credentials
  // find QML MapView component
  m_mapView = findChild<MapQuickView*>("mapView");
  // create a tiled basemap
  ArcGISTiledLayer* tiledLayer = new ArcGISTiledLayer(m_serviceUrl, this);
  Basemap* basemap = new Basemap(tiledLayer, this);
  // create a new map instance
  m_map = new Map(basemap, this);
  // set an initial viewpoint
  Envelope env(11257744, 1682070, 11259005, 1683016, SpatialReference(3857));
  Viewpoint viewpoint(env);
  m_map->setInitialViewpoint(viewpoint);
  // set map on the map view
  m_mapView->setMap(m_map);
  // create the task with the url and load it
  m_exportTileCacheTask = new ExportTileCacheTask(m_exportUrl, this);
  connect(m_exportTileCacheTask, &ExportTileCacheTask::doneLoading, this, [this](Error error)
  {
    if (!error.isEmpty())
    {
      emit updateStatus("Export failed");
      emit hideWindow(5000, false);
    }
  });
  connect(m_mapView, &MapQuickView::viewpointChanged, this, [this]()
  {
    qDebug() << m_mapView->currentViewpoint(ViewpointType::BoundingGeometry).targetGeometry().toJson();
  });
}

The rest of your code should work as is hopefully - please let me know if this is working for you!

Luke

0 Kudos
NicholasLiccini
Emerging Contributor

Luke,

Thank you for the sample code. I have integrated that into what I have but still no luck. Just to be clear, your code should try to create the basemap, then throw an AuthenticationChallenge which would then be picked up by the AuthenticationView in the QML where you can log in and the basemap would then load, correct?

As of now, my issue is that the AuthenticationView will not create properly, and it keeps giving me the same two errors:

file:///C:/Program Files (x86)/ArcGIS SDKs/Qt100.1/sdk/toolkit/Import/Esri/ArcGISRuntime/Toolkit/Dia...: QML Connections: Cannot assign to non-existent property "onAuthenticationChallenge"

file:///C:/Program Files (x86)/ArcGIS SDKs/Qt100.1/sdk/toolkit/Import/Esri/ArcGISRuntime/Toolkit/Dia...: Unable to assign [undefined] to QObject*

If this issue with the AuthenticationView is solved, I should be able to enter in my ArcGIS Developer credentials and the map would load, correct? 

Thanks for all the help!

Nick

0 Kudos