How to download all feature layers without selecting area through IOS SDK.

2725
28
03-27-2017 07:10 AM
KamalMittal
New Contributor III

Hi,

I want to generate a geodatabase which contain all feature layers data so that I can use that database when there is no internet connection but I do not want to give an option to user to select area of interest.  All feature layer data should be  download automatically in background. 

Thanks,

Kamal

Tags (1)
0 Kudos
28 Replies
Nicholas-Furness
Esri Regular Contributor

Hi Kamal.

For each layer you specify in the AGSGenerateGeodatabaseParameters object that you pass to generateJobWithParameters(), you can specify an AGSGenerateLayerOption object. That object has a useGeometry property that you can set to false.

0 Kudos
KamalMittal
New Contributor III

Below is the code which I am using to download feature layer. Right now I am getting exception "

Geometry cannot be null in generate geodatabase parameters.

". Actually I want to download all feature layer data automatically in background without user selecting area.

private let FEATURE_SERVICE_URL = NSURL(string: "https://services7.arcgis.com/JRY73mi2cJ1KeR7T/arcgis/rest/services/NewYorkHospitalLayer/FeatureServe...")!

    private var syncTask:AGSGeodatabaseSyncTask!

    private var generateJob:AGSGenerateGeodatabaseJob!

    private var generatedGeodatabase:AGSGeodatabase!

    

    override func viewDidLoad() {

        super.viewDidLoad()

        

    

        self.map = AGSMap(basemap: AGSBasemap.streetsBasemap())

        

        self.syncTask = AGSGeodatabaseSyncTask(URL: self.FEATURE_SERVICE_URL)

        

        self.addFeatureLayers()

        self.mapView.map = self.map

        self.generateGeodatabase()

    }

        

    func addFeatureLayers() {

        

        self.syncTask.loadWithCompletion { [weak self] (error) -> Void in

            if let error = error {

                print("Could not load feature service \(error)")

                

            } else {

                guard let weakSelf = self else {

                    return

                }

                

                for (index, layerInfo) in weakSelf.syncTask.featureServiceInfo!.layerInfos.enumerate().reverse() {

                    

                    //For each layer in the serice, add a layer to the map

                    let layerURL = weakSelf.FEATURE_SERVICE_URL.URLByAppendingPathComponent(String(index))

                    let featureTable = AGSServiceFeatureTable(URL:layerURL!)

                    let featureLayer = AGSFeatureLayer(featureTable: featureTable)

                    featureLayer.name = layerInfo.name

                    featureLayer.opacity = 0.65

                    weakSelf.map.operationalLayers.addObject(featureLayer)

                }

                

            }

        }

    }

func generateGeodatabase() {

        //create AGSGenerateLayerOption objects with selected layerIds

        var layerOptions = [AGSGenerateLayerOption]()

    

            let layerOption = AGSGenerateLayerOption(layerID: 0)

            layerOption.useGeometry = false

            layerOptions.append(layerOption)

        

        

        //parameters

        let params = AGSGenerateGeodatabaseParameters()

    

        params.layerOptions = layerOptions

        params.returnAttachments = true

        params.attachmentSyncDirection = .Bidirectional

        

        //name for the geodatabase

        let dateFormatter = NSDateFormatter()

        dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"

        

        let path = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0]

        let fullPath = "\(path)/\(dateFormatter.stringFromDate(NSDate())).geodatabase"

            

        //create a generate job from the sync task

        self.generateJob = self.syncTask.generateJobWithParameters(params, downloadFileURL: NSURL(string: fullPath)!)

        

        //start the job

        self.generateJob.startWithStatusHandler({ (status: AGSJobStatus) -> Void in

            SVProgressHUD.showWithStatus(status.statusString(), maskType: .Gradient)

            

        }) { [weak self] (object: AnyObject?, error: NSError?) -> Void in

            

            if let error = error {

                SVProgressHUD.showErrorWithStatus(error.localizedDescription)

            }

            else {

                SVProgressHUD.dismiss()

               Print("Database generated successfully")

            }

        }

    }

    

0 Kudos
Nicholas-Furness
Esri Regular Contributor

Hey Kamal,

Could you be a little more specific about what error you're getting?

0 Kudos
KamalMittal
New Contributor III

Hi Nicholas,

I have updated my above code and I am getting below exception:

"Geometry cannot be null in generate geodatabase parameters."

 

0 Kudos
YueWu1
by Esri Regular Contributor
Esri Regular Contributor

Hi Kamal Mittal,


Maybe you can try this:

1. Based on our REST API, the Create Replica expects you to have geometry for sure: 

ArcGIS REST API - Create Replica 

  • Envelope simple syntax: geometryType=esriGeometryEnvelope&geometry=<xmin>,<ymin>,<xmax>,<ymax>

2. Then we compare Runtime iOS SDK how to get Envelope. Then we will found this Class: ArcGIS Runtime SDK for iOS: AGSEnvelope Class Reference 

3. Then we check generate Geodatabase Class, we saw this property: generateGeodatabaseExtent property 

4. The rest we need to do is how to pass the AGSMapView's AGSEnvelope as a parameter to generateGeodatabaseExtent.

5. In AGSMapView Class Reference there is a  visibleArea property. it is a AGSPolygon type, if you check this class, you will find there is a property called AGSEnvelope property in AGSPolygon 

6. So technically you can use this line of code to assign the mapview extent as generate Geodatabase Extent:

generateGeodatabaseExtent = self.mapview.visibleArea.extent‍

http://resources.arcgis.com/en/help/arcgis-rest-api/#/Create_Replica/02r3000000rp000000/<strong></st...

Hope this can help.


Nathan

0 Kudos
Nicholas-Furness
Esri Regular Contributor

Thanks for the additional info, Yue Wu.

Kamal Mittal To clarify, even though you need to provide a geometry to the AGSGenerateGeodatabaseParameters.extent property, setting the layer options as you did should override that and return all data.

0 Kudos
KamalMittal
New Contributor III

Thanks Nicholas. Now I am able to get all layer data. There is one question for you. Can I include multiple feature layer url's data into same geodatabase and can use it when offline?.

Thanks,

Kamal

0 Kudos
KamalMittal
New Contributor III

Thanks Yue Wu for good explanation

0 Kudos
YueWu1
by Esri Regular Contributor
Esri Regular Contributor

My pleasure. As long as your feature layers are all come from the same feature service url, for example: Sync/WildfireSync (FeatureServer) 

In this feature service, there are three feature layers, and you can use REST to create Replica and the download offline geodatabase can be use in offline mode as long as you setup all three layers to be downloaded.

0 Kudos