Create mobile geodatabase

View on GitHub

Create and share a mobile geodatabase.

Create mobile geodatabase View geodatabase table

Use case

A mobile geodatabase is a collection of various types of GIS datasets contained in a single file (.geodatabase) on disk that can store, query, and manage spatial and nonspatial data. Mobile geodatabases are stored in a SQLite database and can contain up to 2 TB of portable data. Users can create, edit and share mobile geodatabases across ArcGIS Pro, ArcGIS Maps SDKs for Native Apps, or any SQL software. These mobile geodatabases support both viewing and editing and enable new offline editing workflows that don't require a feature service.

For example, a user would like to track the location of their device at various intervals to generate a heat map of the most visited locations. The user can add each location as a feature to a table and generate a mobile geodatabase. The user can then instantly share the mobile geodatabase to ArcGIS Pro to generate a heat map using the recorded locations stored as a geodatabase feature table.

How to use the sample

Tap on the map to add a feature symbolizing the user's location. Tap "View Table" to view the contents of the geodatabase feature table. Once you have added the location points to the map, tap on the share button to retrieve the .geodatabase file which can then be imported into ArcGIS Pro or opened in an ArcGIS Maps SDK application.

How it works

  1. Create the Geodatabase from the mobile geodatabase location on file.
  2. Create a new TableDescription and add the list of FieldDescriptions to the table description.
  3. Create a GeodatabaseFeatureTable in the geodatabase from the TableDescription using Geodatabase.makeTable(description:).
  4. Create a feature on the selected map point using GeodatabaseFeatureTable.makeFeature(attributes:geometry:).
  5. Add the feature to the table using GeodatabaseFeatureTable.add(_:).
  6. Each feature added to the GeodatabaseFeatureTable is committed to the mobile geodatabase file.
  7. Close the mobile geodatabase to safely share the ".geodatabase" file using Geodatabase.close()

Relevant API

  • ArcGISFeature
  • FeatureLayer
  • FeatureTable
  • FieldDescription
  • Geodatabase
  • GeodatabaseFeatureTable
  • TableDescription

Additional information

Learn more about mobile geodatabases and how to utilize them on the ArcGIS Pro documentation page. The following mobile geodatabase behaviors are supported in the ArcGIS Maps SDKs for Native Apps: annotation, attachments, attribute rules, contingent values, dimensions, domains, feature-linked annotation, subtypes, utility network and relationship classes.

Learn more about the types of fields supported with mobile geodatabases on the ArcGIS Pro documentation page.

Tags

arcgis pro, database, feature, feature table, geodatabase, mobile geodatabase, sqlite

Sample Code

CreateMobileGeodatabaseView.swiftCreateMobileGeodatabaseView.swiftCreateMobileGeodatabaseView.Model.swift
Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
// Copyright 2023 Esri
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import ArcGIS
import SwiftUI

struct CreateMobileGeodatabaseView: View {
    /// The view model for the sample.
    @StateObject private var model = Model()

    /// The point on the map where the user tapped.
    @State private var tapLocation: Point?

    /// A Boolean value indicating whether the feature table sheet is showing.
    @State private var tableSheetIsShowing = false

    /// A Boolean value indicating whether the file explorer interface is showing
    @State private var fileExporterIsShowing = false

    /// The error shown in the error alert.
    @State private var error: Error?

    var body: some View {
        MapView(map: model.map)
            .onSingleTapGesture { _, mapPoint in
                tapLocation = mapPoint
            }
            .task(id: tapLocation) {
                guard let tapLocation else { return }
                do {
                    // Add a feature at the tap location.
                    try await model.addFeature(at: tapLocation)
                } catch {
                    self.error = error
                }
            }
            .task(id: model.features.isEmpty) {
                do {
                    // Create a new feature table when the features are reset.
                    if model.features.isEmpty {
                        try await model.createFeatureTable()
                    }
                } catch {
                    self.error = error
                }
            }
            .overlay(alignment: .top) {
                Text("Number of features added: \(model.features.count)")
                    .frame(maxWidth: .infinity, alignment: .center)
                    .padding(8)
                    .background(.thinMaterial, ignoresSafeAreaEdges: .horizontal)
            }
            .toolbar {
                ToolbarItemGroup(placement: .bottomBar) {
                    tableButton
                        .disabled(model.features.isEmpty)

                    Spacer()

                    Button {
                        fileExporterIsShowing = true
                    } label: {
                        Label("Export File", systemImage: "square.and.arrow.up")
                    }
                    .disabled(model.features.isEmpty)
                    .fileExporter(
                        isPresented: $fileExporterIsShowing,
                        document: model.geodatabaseFile,
                        contentType: .geodatabase
                    ) { result in
                        switch result {
                        case .success:
                            do {
                                try model.resetFeatures()
                            } catch {
                                self.error = error
                            }
                        case .failure(let error):
                            self.error = error
                        }
                    }
                }
            }
            .errorAlert(presentingError: $error)
    }
}

private extension CreateMobileGeodatabaseView {
    /// The button that brings up the feature table sheet.
    @ViewBuilder var tableButton: some View {
        /// The button to bring up the sheet.
        let button = Button("View Table") {
            tableSheetIsShowing = true
        }

        if #available(iOS 16, *) {
            button
                .popover(isPresented: $tableSheetIsShowing, arrowEdge: .bottom) {
                    tableList
                        .presentationDetents([.fraction(0.5)])
#if targetEnvironment(macCatalyst)
                        .frame(minWidth: 300, minHeight: 270)
#else
                        .frame(minWidth: 320, minHeight: 390)
#endif
                }
        } else {
            button
                .sheet(isPresented: $tableSheetIsShowing) {
                    tableList
                }
        }
    }

    /// The list of features in the feature table.
    var tableList: some View {
        NavigationView {
            List {
                Section("OID and Collection Timestamp") {
                    ForEach(model.features, id: \.self) { feature in
                        HStack {
                            Text(String(feature.oid))
                                .padding(.trailing, 8)
                            Text(feature.timestamp.formatted(.collectionTimestamp))
                        }
                    }
                }
            }
            .navigationTitle("Feature Table")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .confirmationAction) {
                    Button("Done") {
                        tableSheetIsShowing = false
                    }
                }
            }
        }
        .navigationViewStyle(.stack)
    }
}

private extension FormatStyle where Self == Date.VerbatimFormatStyle {
    /// The format style for a collection timestamp of a feature in a feature table.
    static var collectionTimestamp: Self {
        .init(
            format: """
                \(weekday: .abbreviated) \
                \(month: .abbreviated) \
                \(day: .defaultDigits) \
                \(hour: .twoDigits(clock: .twentyFourHour, hourCycle: .oneBased)):\
                \(minute: .twoDigits):\
                \(second: .twoDigits) \
                \(timeZone: .specificName(.short)) \
                \(year: .defaultDigits)
                """,
            locale: .current,
            timeZone: .current,
            calendar: .current
        )
    }
}

#Preview {
    NavigationView {
        CreateMobileGeodatabaseView()
    }
}

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.