Kyle Day committed Sep 10, 2020 1 # ThinkGeo Mobile Maps  Ben Bai committed Apr 12, 2020 2   Kyle Day committed Sep 10, 2020 3 Welcome, we're glad you're here! If you're new to ThinkGeo's Mobile Maps, we suggest that you start by taking a look at our quickstart guide below. This will introduce you to getting a nice looking map up and running with some external data and styling. After reviewing this, we strongly recommend that you check out our HowDoI samples for [Xamarin.Forms](https://gitlab.com/thinkgeo/public/thinkgeo-mobile-maps/-/tree/master/samples/xamarin-forms/HowDoISample). It's packed with examples covering nearly everything you can do with our Mobile Maps control.  Kyle Day committed Apr 03, 2020 4   Ryan Duan committed Apr 27, 2020 5 6 ## Repository Layout  David Rehagen committed Apr 29, 2020 7 /docs: An offline version the API documentation HTML pages.  Ryan Duan committed Apr 27, 2020 8 9 10  /samples: A collection of feature by feature samples.  David Rehagen committed Apr 29, 2020 11 /assets: Any assets needed for the readme.md.  Ryan Duan committed Apr 27, 2020 12 13  README.md: A quick start guide to show you how to quickly get up and running.  Kyle Day committed Apr 03, 2020 14   Kyle Day committed Sep 10, 2020 15 ## Samples  Kyle Day committed Apr 03, 2020 16 17 18  We have a number of samples for both Android and iOS that show off ThinkGeo Mobile Maps' full capabilities. You can use these samples as a starting point for your own application, or simply reference them for how to use our controls using best practices.  Ryan Duan committed May 11, 2020 19 20 - [iOS samples](https://gitlab.com/thinkgeo/public/thinkgeo-mobile-maps/-/tree/master/samples/ios) - [Android samples](https://gitlab.com/thinkgeo/public/thinkgeo-mobile-maps/-/tree/master/samples/android)  Kyle Day committed Apr 03, 2020 21   Kyle Day committed Sep 10, 2020 22 23 24 25 26 27 28 29 30 31 ## Quickstart Guides - [Xamarin.Forms Quickstart Guide](#xamarinforms-quickstart-guide) - [Android Quickstart Guide](#quick-start-display-a-simple-map-on-android) - [iOS Quickstart Guide](#quick-start-display-a-simple-map-on-ios) ## Xamarin.Forms Quickstart Guide This will introduce you to ThinkGeo Mobile Maps by getting a nice looking map up and running with ThinkGeo background map along with some external data on a Xamarin.Forms application. By the end of this guide, you should have a basic understanding of how to use the Mobile Maps controls.  Kyle Day committed Sep 10, 2020 32 ![Simple Map](https://gitlab.com/thinkgeo/public/thinkgeo-mobile-maps/-/raw/master/assets/xamarinforms_quickstart_screenshot.png)  Kyle Day committed Sep 10, 2020 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 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197  ### Step 1: Install Prerequisites Visual Studio will help guide you to setup your XamarinForms environment for both iOS and Android. Refer to the [Xamarin for Visual Studio guide](https://docs.microsoft.com/en-us/xamarin/get-started/installation) for more info. #### Android Prerequisites - Xamarin - The [Android SDK](https://docs.microsoft.com/en-us/xamarin/android/get-started/installation/android-sdk) - An [Android Emulator](https://docs.microsoft.com/en-us/xamarin/android/get-started/installation/android-emulator/device-manager) #### iOS Prerequisites To develop on Mac, you need: - XCode, which provides iOS emulator. - A development IDE, it could be Visual Studio for Mac, Xamarin Studio or others. - Xamarin. - A provisioning profile is needed if you want to test on an iOS device. To develop on Windows, you need: - A development IDE, such as Visual Studio or Xamarin Studio - Xamarin. - A Mac machine with XCode installed and on the same network as your Windows machine. ### Step 2: Set Up a New Project Create a new project and select the Mobile App (Xamarin.Forms) project template. Name your application ThinkGeoMobileQuickstart and select the Blank application project template. Once created, there will be 3 projects in the solution: - ThinkGeoMobileQuickstart - The is where our shared will live - ThinkGeoMobileQuickstart.Android - Android specific code (no modifications will be needed to this project in this demo) - ThinkGeoMobileQuickstart.iOS - iOS specific code (no modifications will be needed to this project in this demo) Go ahead and run the application. By default, Visual Studio will set you up with an Android emulator if you do not already have one. If you wish to debug the application for iOS, set your starting project to ThinkGeoMobileQuickstart.iOS and Visual Studio will assist you to connect to your remote Mac machine. ### Step 3: Implement the code Once your blank application is up and running, install the following NuGet packages for each project: - ThinkGeoMobileQuickstart - ThinkGeo.UI.XamarinForms - ThinkGeoMobileQuickstart.Android - ThinkGeo.UI.XamarinForms.Android - ThinkGeoMobileQuickstart.iOS - ThinkGeo.UI.XamarinForms.iOS Open the MainPage.xaml found in the ThinkGeoMobileQuickstart project and add the following XML namespace to the ContentPage: xml xmlns:ThinkGeo="clr-namespace:ThinkGeo.UI.XamarinForms;assembly=ThinkGeo.UI.XamarinForms"  Next, replace all elements in the StackLayout with a single MapView: xml  Now that the MapView has been added to the MainPage, we need to setup the map on the code side. For that, you will need to add two usings to MainPage.xaml.cs: cs // MainPage.xaml.cs using ThinkGeo.Core; using ThinkGeo.UI.XamarinForms;  Next, override the ContentPage's OnAppearing method to setup the map: cs // MainPage.xaml.cs protected override void OnAppearing() { base.OnAppearing(); // Set the map's unit of measurement to meters(Spherical Mercator) mapView.MapUnit = GeographyUnit.Meter; // Add Cloud Maps as a background overlay. The keys provided below are just demo keys var thinkGeoCloudVectorMapsOverlay = new ThinkGeoCloudVectorMapsOverlay("9ap16imkD_V7fsvDW9I8r8ULxgAB50BX_BnafMEBcKg~", "vtVao9zAcOj00UlGcK7U-efLANfeJKzlPuDB9nw7Bp4K4UxU_PdRDg~~", ThinkGeoCloudVectorMapsMapType.Light); mapView.Overlays.Add(thinkGeoCloudVectorMapsOverlay); // Set the map extent mapView.CurrentExtent = new RectangleShape(-10000000, 10000000, 10000000, -10000000); }  Build the project and make sure it builds successfully. ### Step 4: Activate a Free Evaluation License If you try to run the application now, "A license is needed" exception will be thrown if a valid .mapsuitelicense file is not found. A free 60-day license can be created using the following steps: #### Launching ThinkGeo Product Center 1. Run ThinkGeo.ProductCenter.exe to open the product center. This can be found in the bin folder of the ThinkGeoMobileQuickstart.Android or ThinkGeoMobileQuickstart.iOS project. (ThinkGeo.ProductCenter.exe can only be opened on Windows, there's a CLI version for Mac.) 1. Click on Log In in the upper-right corner, input the username/password to login or click Create a new account to create a free ThinkGeo account. #### Activating and Creating an Android License 1. Click on the ThinkGeo UI Mobile for Android tab and activate an evaluation license. 1. To generate a runtime license for the sample app, you'll need to find the package name for your sample project. In Visual Studio, this can be found by right-clicking on the ThinkGeoMobileQuickstart.Android project in the solution explorer and navigating to Properties -> Android Manifest -> Package Name 1. Copy the Package Name to the Runtime License input box to the right of the Product Center and click Create. Save the newly created license to the Assets folder of the solution (ThinkGeoMobileQuickstart.Android\Assets). 1. Add the license to the project in the solution explorer by right-clicking on the Assets folder and selecting Add -> Existing Item. 1. Right-click on the license and select Properties. Ensure that the Build Action is set to AndroidAsset #### Activating and Creating an iOS License 1. Click the ThinkGeo UI Mobile for iOS tile and then click on Start Evaluation (or Activate License if you already have purchased a full license). Now you can see a textbox with text placeholder Bundle Identifer on the right. 1. Get the project's bundle identifier in info.plist, copy and paste it to the 'bundle dentifier' textbox in product center. 1. Click 'Create' and save the license file (the file name would be .mapsuitelicense) to the solution's root folder. 1. Add the license to the project in the solution explorer by right-clicking the project and elect Add -> Existing Item.... 1. Right-click the license file in the solution explorer, select Properties and change the Build Action to BundleResource. Rebuild the solution after adding the license files and then run the application. If all is well, you should see a map! ### Step 5: Adding an External Data Source Now let's add an external data source (Shape File) to the map. 1. Download [WorldCapitals.zip](https://gitlab.com/thinkgeo/public/thinkgeo-mobile-maps/-/tree/master/assets/WorldCapitals.zip) shapefile and unzip it in your project under a new folder called SampleData. 1. Include those files to the project. Multi-select them and change the Build Action to "EmbeddedResource". Unfortunately, reading from the filesystem is a bit tricky with Xamarin. So, we will need to take our EmbeddedResource shapefiles and copy them to the LocalApplicationData directory before we can display them on the map. To do this, we can run some code on application startup in App.xaml.cs: cs // App.xaml.cs public App() { InitializeComponent(); } protected override async void OnStart() { await CopyAssets(); MainPage = new MainPage(); // Moved from App constructor } /// /// Copies all embedded resources to the LocalApplicationData directory /// private async Task CopyAssets() { var assembly = IntrospectionExtensions.GetTypeInfo(typeof(App)).Assembly; foreach (var resourceName in assembly.GetManifestResourceNames()) { string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); // Change the replace value to whatever your project's name is string[] parts = resourceName.Replace("ThinkGeoMobileQuickstart.", "").Split('.'); string localPath = ""; for (int i = 0; i < parts.Length; i++) { // Default delimiter to '/' for the directory structure var delimiter = "/"; // Use '.' delimiter for file extensions  Kyle Day committed Sep 10, 2020 198 199 200 201  if (i == parts.Length - 1) delimiter = "."; // Don't use a delimiter for the first part if (i == 0) delimiter = "";  Kyle Day committed Sep 10, 2020 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223  localPath += \$"{delimiter}{parts[i]}"; } string targetFilePath = Path.Combine(appDataPath, localPath); string targetDir = Path.GetDirectoryName(targetFilePath); if (!Directory.Exists(targetDir)) Directory.CreateDirectory(targetDir); if (!File.Exists(targetFilePath)) { using (var targetStream = File.Create(targetFilePath)) { Stream sourceStream = assembly.GetManifestResourceStream(resourceName); await sourceStream.CopyToAsync(targetStream); sourceStream.Close(); } } } }   Kyle Day committed Sep 10, 2020 224 There's a few important notes about the above code. First, we need to copy these files asynchronously, so we needed to add the async keyword to the OnStart method. Second, we moved the assignment of the MainPage to the OnStart method after we finished copying the assets. Finally, EmbeddedResources are always named ProjectName.Path.To.File.txt. So, when we copy the files to the filesystem, we are stripping ProjectName..  Kyle Day committed Sep 10, 2020 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252  Now, that we can copy over the WorldCapital shapefile, let's add it to the map: cs // MainPage.xaml.cs protected override void OnAppearing() { base.OnAppearing(); //... // Create a new Feature Layer using the WorldCapitals.shp Shapefile. ShapeFileFeatureLayer worldCapitalsFeatureLayer = new ShapeFileFeatureLayer(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "SampleData/WorldCapitals.shp")); // Set the pointstyle to black circle with the size of 8. worldCapitalsFeatureLayer.ZoomLevelSet.ZoomLevel01.DefaultPointStyle = PointStyle.CreateSimpleCircleStyle(GeoColors.White, 8, GeoColors.Black); // Apply the point style from zoomlevel01 to zoomlevel20, that's across all the zoomlevels. worldCapitalsFeatureLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20; // Convert the world capital featurelayer from DecimalDegrees, which is the projection of the raw data, to Spherical Mercator, which is the projection of the map. worldCapitalsFeatureLayer.FeatureSource.ProjectionConverter = new ProjectionConverter(Projection.GetDecimalDegreesProjString(), Projection.GetSphericalMercatorProjString()); // Add the Layer to an Overlay and add the overlay to the map. LayerOverlay layerOverlay = new LayerOverlay(); layerOverlay.Layers.Add(worldCapitalsFeatureLayer); mapView.Overlays.Add(layerOverlay); }   Kyle Day committed Sep 10, 2020 253 254 Now, when you run the application, the shapefiles will be added to the LocalApplicationData directory which then allows it to be displayed on the map!  Kyle Day committed Sep 10, 2020 255 256 257 258 259 260 261 262 263 ### Summary You now know the basics of using the ThinkGeo Map controls and are able to get started adding functionality into your own applications. Let's recap what we have learned about the object relationships and how the pieces of ThinkGeo UI work together: 1. It is of the utmost importance that the units (feet, meters, decimal degrees, etc.) be set properly for the Map control based on the data. 1. FeatureLayers provide the data used by a Map control to render a map. 1. A Map is the basic control that contains all of the other objects that are used to tell how the map is to be rendered. 1. A Map has many layers. A Layer correlates one-to-one with a single data source and typically of one type (point, polygon, line etc). 1. A FeatureLayer can have several ZoomLevels. ZoomLevels help to define ranges (upper and lower) of when a Layer should be shown or hidden.  Kyle Day committed Apr 03, 2020 264   Kyle Day committed Sep 10, 2020 265 You are now in a great position to look over the [other samples available](https://gitlab.com/thinkgeo/public/thinkgeo-mobile-maps/-/tree/master/samples/xamarin-forms) and explore our other features.  David Rehagen committed Apr 29, 2020 266 267 268 269 270  ## Quick Start: Display a Simple Map on iOS This will introduce you to ThinkGeo Mobile Maps by getting a nice looking map up and running with ThinkGeo background map along with some external data on a Xamarin iOS application. By the end of this guide, you should have a basic understanding of how to use the Mobile Maps controls.  Ryan Duan committed May 18, 2020 271 ![Simple Map](https://gitlab.com/thinkgeo/public/thinkgeo-mobile-maps/-/raw/master/assets/ios_quickstart_shapefile_pointstyle_screenshot.png)  David Rehagen committed Apr 29, 2020 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292  ### Step 1: Install Prerequisites In order to develop and debug Xamarin iOS applications, you'll need to have a few prerequisites set up. To develop on Mac, You need: * XCode, which provides iOS emulator. * A development IDE, it could be Visual Studio for Mac, Xamarin Studio or others. * Xamarin. It has been installed by default in Visual Studio for Mac or Xamarin Studio, might need to be manually installed in other IDEs. * A provisioning profile is needed if you want to test on an iOS device. To develop on Windows, you need: * A Mac Machine in the same network as your build server. XCode needs to be installed on that machine. * And on your Windows machine, you need: * A development IDE, such as Visual Studio or Xamarin Studio * Xamarin. Make sure it is well installed. Even it sounds complicated, Microsoft in fact has made it very straightforward to connect to a MAC and develop Xamarin on Windows. So if you are a .NET developer get used to Visual Studio, feel free to stay on Windows for Xamarin development. This quick start guide is based on Visual Studio on Windows and there's no problem at all to start your application on Mac.  Ben Bai committed May 04, 2020 293 294 295 296 297 298 Here a few handy links for installation and setup of these prerequisites using Visual Studio: [Xamarin for Visual Studio](https://docs.microsoft.com/en-us/xamarin/get-started/installation) [Xamarin.iOS Installation](https://docs.microsoft.com/en-us/xamarin/ios/get-started/installation/)  David Rehagen committed Apr 29, 2020 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 ### Step 2: Set Up a New Project Once these prerequisites have been installed, let's create a new **iOS App (Xamarin)** project in Visual Studio and select **Single View App** template. Here is a [guide to creating a sample project](https://docs.microsoft.com/en-us/xamarin/iOS/get-started/hello-iOS/hello-iOS-quickstart) for reference. Go ahead and run the project once it is created, and Visual Studio will help you to locate the MacOS server and initialize the connection. If everything goes well, you should see the iOS emulator get launched on Windows and the default project runs in the emulator. ### Step 3: Implement the code Install NuGet Package ThinkGeo.UI.iOS to the project: shell dotnet add package ThinkGeo.UI.iOS  Add the required usings to the ViewController.cs file: csharp using ThinkGeo.Core; using ThinkGeo.iOS.UI  Update ViewDidLoad() method in ViewController.cs as following: csharp public override void ViewDidLoad () { base.ViewDidLoad (); // Perform any additional setup after loading the view, typically from a nib. // Creat a new MapView, which is the canvas of the map, and add it to the View. MapView mapView = new MapView(View.Frame); View.AddSubview(mapView); // Set the Map Unit to Meter and set the map's current extent to North America. mapView.MapUnit = GeographyUnit.Meter; mapView.CurrentExtent = new RectangleShape(-13939426, 6701997, -7812401, 2626987); // Create a new ThinkGeoCloud Overlay using Client ID / Client Secret, and add it the overlay to MapView. string clientKey = "9ap16imkD_V7fsvDW9I8r8ULxgAB50BX_BnafMEBcKg~"; string secret = "vtVao9zAcOj00UlGcK7U-efLANfeJKzlPuDB9nw7Bp4K4UxU_PdRDg~~"; ThinkGeoCloudVectorMapsOverlay thinkGeoCloudMapsOverlay = new ThinkGeoCloudVectorMapsOverlay(clientKey, secret); mapView.Overlays.Add(thinkGeoCloudMapsOverlay); mapView.Refresh(); }  ### Step 4: Apply an Evaluation License for Free Build the project and make sure it builds through. "A license is needed" exception will be thrown if you run it though and here is how to fix it: 1. Run ThinkGeo.ProductCenter.exe to open the product center. This can be found in the bin folder of the project. (ThinkGeo.ProductCenter.exe can only be opened on Windows, there's a CLI version for Mac.) 1. Click on Log In in the upper-right corner, input the username/password to login or click Create a new account to create a ThinkGeo account for free. 1. Once logged in, click on ThinkGeo UI Mobile for iOS tile and then click on Start Evaluation(it would be Activate License if you already purchased), now you can see a textbox with textholder Bundle Identifer on the right. 1. Now we need to generate a license for the project following the steps below: * Get the project's bundle identifier in info.plist, copy and paste it to the 'bundle dentifier' textbox in product center. * Hit 'Create' and save the license file (the file name would be bundle-identifer.apsuitelicense) to the solution's root folder. * Add the license to the project in the solution explorer by right-clicking the project and elect Add -> Existing Item.... * Right-click the license file in the solution explorer, select Properties and change the Build Action to BundleResource. Now go ahead and run the application and the map will be displayed properly. ### Step 5: Adding an External Data Source Now let's add an external data source (Shape File) to the map.  Ryan Duan committed May 11, 2020 365 1. Download [WorldCapitals.zip](https://gitlab.com/thinkgeo/public/thinkgeo-mobile-maps/-/tree/master/assets/WorldCapitals.zip) shapefile and unzip it in your project under a new folder called SampleData.  David Rehagen committed Apr 29, 2020 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 1. Include those files to the project. Multi-select them and change the Build Action to "Content". 1. Now add the following code to ViewDidLoad() method. csharp // Create a new Feature Layer using the WorldCapitals.shp Shapefile. ShapeFileFeatureLayer worldCapitalsFeatureLayer = new ShapeFileFeatureLayer("SampleData/WorldCapitals.shp"); // Set the pointstyle to black circle with the size of 8. worldCapitalsFeatureLayer.ZoomLevelSet.ZoomLevel01.DefaultPointStyle = PointStyle.CreateSimpleCircleStyle(GeoColors.White, 8, GeoColors.Black); // Apply the point style from zoomlevel01 to zoomlevel20, that's accross all the zoomlevels. worldCapitalsFeatureLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20; // Convert the world capital featurelay from DecimalDegrees, which is the projection of the raw data, to Spherical Mercator, which is the projection of the map. worldCapitalsFeatureLayer.FeatureSource.ProjectionConverter = new ProjectionConverter(Projection.GetDecimalDegreesProjString(), Projection.GetSphericalMercatorProjString()); // Add the Layer to an Overlay and add the overlay to the map. LayerOverlay layerOverlay = new LayerOverlay(); layerOverlay.Layers.Add(worldCapitalsFeatureLayer); mapView.Overlays.Add(layerOverlay);  ### iOS Summary You now know the basics of using the ThinkGeo Map controls and are able to get started adding functionality into your own applications. Let's recap what we have learned about the object relationships and how the pieces of ThinkGeo UI work together: 1. It is of the utmost importance that the units (feet, meters, decimal degrees, etc.) be set properly for the Map control based on the data. 1. FeatureLayers provide the data used by a Map control to render a map. 1. A Map is the basic control that contains all of the other objects that are used to tell how the map is to be rendered. 1. A Map has many layers. A Layer correlates one-to-one with a single data source and typically of one type (point, polygon, line etc). 1. A FeatureLayer can have several ZoomLevels. ZoomLevels help to define ranges (upper and lower) of when a Layer should be shown or hidden.  Ryan Duan committed May 11, 2020 396 You are now in a great position to look over the [other samples available](https://gitlab.com/thinkgeo/public/thinkgeo-mobile-maps/-/tree/master/samples/ios) and explore our other features.  David Rehagen committed Apr 29, 2020 397 398  ## Quick Start: Display a Simple Map on Android  Kyle Day committed Apr 03, 2020 399   Kyle Day committed Apr 03, 2020 400 401 This will introduce you to ThinkGeo Mobile Maps by getting a nice looking map up and running with some external data and styling on a Xamarin Android application. By the end of this guide, you should have a basic understanding of how to use the Mobile Maps controls.  Ryan Duan committed May 18, 2020 402 ![alt text](https://gitlab.com/thinkgeo/public/thinkgeo-mobile-maps/-/raw/master/assets/quickstart_shapefile_pointstyle_screenshot.PNG "Simple Map")  Ryan Duan committed Apr 27, 2020 403 404 405 406  ### Step 1: Set Up Prerequisites In order to develop and debug Xamarin Android applications, you'll need to have a few prerequisites set up. These include:  Kyle Day committed Apr 03, 2020 407   Ryan Duan committed Apr 27, 2020 408 409 410 * Xamarin * The Android SDK * An Android emulator  Kyle Day committed Apr 03, 2020 411   Ryan Duan committed Apr 27, 2020 412 Here a few handy links for installation and setup of these prerequisites using Visual Studio:  Kyle Day committed Apr 03, 2020 413   Ryan Duan committed Apr 27, 2020 414 [Xamarin for Visual Studio](https://docs.microsoft.com/en-us/xamarin/get-started/installation)  Ryan Duan committed Apr 27, 2020 415   Ryan Duan committed Apr 27, 2020 416 [Android SDK](https://docs.microsoft.com/en-us/xamarin/android/get-started/installation/android-sdk)  Ryan Duan committed Apr 27, 2020 417   Ryan Duan committed Apr 27, 2020 418 [Android Emulator](https://docs.microsoft.com/en-us/xamarin/android/get-started/installation/android-emulator/device-manager)  Kyle Day committed Apr 03, 2020 419   David Rehagen committed Apr 29, 2020 420 ### Step 2: Set Up a New Project  Kyle Day committed Apr 03, 2020 421   David Rehagen committed Apr 29, 2020 422 Once these prerequisites have been installed, you'll need to create a new **Xamarin Android** project in your editor of choice. Please refer to your editor's instructions on how to create this project. Here is a [guide to creating a sample project](https://docs.microsoft.com/en-us/xamarin/android/get-started/hello-android/hello-android-quickstart) using Visual Studio for reference.  Kyle Day committed Apr 03, 2020 423   David Rehagen committed Apr 29, 2020 424 ### Step 3: Add NuGet Packages  Kyle Day committed Apr 03, 2020 425   Ryan Duan committed May 11, 2020 426 You'll need to install the **ThinkGeo.UI.Android** NuGet package. We strongly suggest you use your editor's [built in NuGet package manager](https://docs.microsoft.com/en-us/nuget/quickstart/install-and-use-a-package-in-visual-studio) if possible. If you're not using an IDE you can [install it via the the dotnet CLI](https://docs.microsoft.com/en-us/nuget/consume-packages/install-use-packages-dotnet-cli) from inside the project folder where your project file exists.  Kyle Day committed Apr 03, 2020 427   Ryan Duan committed Apr 27, 2020 428 429 430 431 shell dotnet add package ThinkGeo.UI.Android   David Rehagen committed Apr 29, 2020 432 ### Step 4: Set up the App Template and add the MapView element  Ryan Duan committed Apr 27, 2020 433   Ryan Duan committed Apr 30, 2020 434 Open up the main app layout file. In Visual Studio, this should be under the path Resources\layout\activity_main.axml, and add the ThinkGeo.UI.Android.MapView element  Kyle Day committed Apr 03, 2020 435 436 437  xml  Ryan Duan committed Apr 30, 2020 438   Ryan Duan committed Apr 30, 2020 447   Kyle Day committed Apr 03, 2020 448 449   David Rehagen committed Apr 29, 2020 450 ### Step 5: Add Namespaces to MainActivity.cs  Kyle Day committed Apr 03, 2020 451   Ryan Duan committed Apr 27, 2020 452 Add the required usings to the MainActivity.cs file:  Kyle Day committed Apr 03, 2020 453   Ryan Duan committed Apr 27, 2020 454 455 csharp using ThinkGeo.Core;  Ryan Duan committed Apr 30, 2020 456 using ThinkGeo.UI.Android;  Ryan Duan committed Apr 27, 2020 457   Kyle Day committed Apr 03, 2020 458   David Rehagen committed Apr 29, 2020 459 ### Step 6: Add the Map Background Overlay  Kyle Day committed Apr 03, 2020 460   Ryan Duan committed Apr 27, 2020 461 Create a new method called ShowMap in the MainActivity.cs file, and add the code below:  Kyle Day committed Apr 03, 2020 462 463  csharp  Ryan Duan committed Apr 27, 2020 464 465 466 467 public void ShowMap() { // Set our view from the "main" layout resource SetContentView(Resource.Layout.activity_main);  Ryan Duan committed Apr 27, 2020 468   Ryan Duan committed Apr 27, 2020 469  MapView androidMap = FindViewById(Resource.Id.androidMap);  Ryan Duan committed Apr 27, 2020 470   Ryan Duan committed Apr 27, 2020 471 472 473 474  // Set the Map Configuration. androidMap.MapUnit = GeographyUnit.Meter; androidMap.ZoomLevelSet = new ThinkGeoCloudMapsZoomLevelSet(); androidMap.CurrentExtent = new RectangleShape(-20000000, 20000000, 20000000, -20000000);  Ryan Duan committed Apr 27, 2020 475   Ryan Duan committed Apr 27, 2020 476 477  // Add the Cloud Maps Overlay ThinkGeoCloudRasterMapsOverlay thinkGeoCloudMapsOverlay = new ThinkGeoCloudRasterMapsOverlay("9ap16imkD_V7fsvDW9I8r8ULxgAB50BX_BnafMEBcKg~", "vtVao9zAcOj00UlGcK7U-efLANfeJKzlPuDB9nw7Bp4K4UxU_PdRDg~~");  Ryan Duan committed Apr 27, 2020 478   Ryan Duan committed Apr 27, 2020 479 480  androidMap.Overlays.Add("CloudRasterMapsOverlay", thinkGeoCloudMapsOverlay); }  Kyle Day committed Apr 03, 2020 481 482   Ryan Duan committed Apr 27, 2020 483 Then, remove the SetContentView call and call this method from the OnCreate method in the MainActivity.cs file:  Kyle Day committed Apr 03, 2020 484 485  csharp  Ryan Duan committed Apr 28, 2020 486 487 // Remove this call from 'OnCreate' // SetContentView(Resource.Layout.activity_main);  Ryan Duan committed Apr 27, 2020 488   Ryan Duan committed Apr 28, 2020 489 490 // Add this call to the 'OnCreate' method ShowMap();  Ryan Duan committed Apr 27, 2020 491   Kyle Day committed Apr 03, 2020 492   David Rehagen committed Apr 29, 2020 493 ### Step 7: Run the Sample & Register For Your Free Evaluation  Kyle Day committed Apr 03, 2020 494   Ryan Duan committed Apr 27, 2020 495 The first time you run the application, you will be presented with an error requiring a ThinkGeo license to proceed with running the app. In order to register and generate a license for this project, you'll need to perform the following steps:  Kyle Day committed Apr 03, 2020 496   David Rehagen committed Apr 29, 2020 497 498 499 500 501 502 503 504 505 1. Run the ThinkGeo.ProductCenter.exe to open the product center. This can be found in the bin folder of your project at path\to\project\bin\Debug\. 1. Click on Log In in the upper-right corner and Create a new account 1. Follow the steps on the website to register for your account 1. Return to Product Center and log in using your new credentials. 1. Click on the ThinkGeo UI Mobile for Android tab and activate an evaluation license. 1. To generate a runtime license for the sample app, you'll need to find the package name for your sample project. In Visual Studio, this can be found by right-clicking on the project in the solution explorer and navigating to Properties -> Android Manifest -> Package Name 1. Copy the Package Name to the Runtime License input box to the right of the Product Center and click Create. Save the mewly created license to the Assets folder of the solution (path\to\project\Assets). 1. Add the license to the project in the solution explorer by right-clicking on the Assets folder and selecting Add -> Existing Item. 1. Right-click on the license and select Properties. Ensure that the Build Action is set to AndroidAsset  Kyle Day committed Apr 03, 2020 506   Ryan Duan committed Apr 27, 2020 507 You should now be able to see your app with our Cloud Maps layer!  Kyle Day committed Apr 03, 2020 508   David Rehagen committed Apr 29, 2020 509 ### Step 8: Adding an External Data Source - Requesting Permissions  Kyle Day committed Apr 03, 2020 510   Ryan Duan committed Apr 27, 2020 511 Now that you have the basic map set up, you can add custom data to the map. Depending on the data, this can be complex or quite simple. We'll be going over the simple basics of adding custom data.  Kyle Day committed Apr 03, 2020 512   Ryan Duan committed May 11, 2020 513 Download the [WorldCapitals.zip](https://gitlab.com/thinkgeo/public/thinkgeo-mobile-maps/-/tree/master/assets/WorldCapitals.zip) shapefile data and unzip it in your project under a new folder in the Assets folder called AppData. In order to move this data into storage on the Android device, we'll need to set up our app to request some basic permissions as well.  Kyle Day committed Apr 03, 2020 514   Ryan Duan committed Apr 27, 2020 515 First, we need to add the required permissions to the Android manifest. This can be done by right-clicking on the project in the solution explorer and navigating to Properties -> Android Manifest, and finding Required Permissions near the bottom of the page. We need to ensure that the READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE options are checked.  Kyle Day committed Apr 03, 2020 516   Ryan Duan committed Apr 27, 2020 517 Next, we need to set up the method to request permissions. Add the following fields to your MainActivity class:  Kyle Day committed Apr 03, 2020 518   Kyle Day committed Apr 03, 2020 519 csharp  Ryan Duan committed Apr 27, 2020 520 521 522 523 524 525 readonly string[] StoragePermissions = { Manifest.Permission.ReadExternalStorage, Manifest.Permission.WriteExternalStorage }; const int RequestStorageId = 0;  Kyle Day committed Apr 03, 2020 526   Kyle Day committed Apr 03, 2020 527   Ryan Duan committed Apr 27, 2020 528 Add the following usings:  Kyle Day committed Apr 03, 2020 529   Kyle Day committed Apr 03, 2020 530 csharp  Ryan Duan committed Apr 27, 2020 531 532 using Android; using Android.Content.PM;  Kyle Day committed Apr 03, 2020 533   Kyle Day committed Apr 03, 2020 534   Ryan Duan committed Apr 27, 2020 535 Then, add the following method to your MainActivity.cs class. This method will handle requesting permissions:  Kyle Day committed Apr 03, 2020 536   Kyle Day committed Apr 03, 2020 537 csharp  Ryan Duan committed Apr 27, 2020 538 539 540 541 public void RequestRequiredPermissions() { const string readPermission = Manifest.Permission.ReadExternalStorage; const string writePermission = Manifest.Permission.WriteExternalStorage;  Ryan Duan committed Apr 27, 2020 542   Ryan Duan committed Apr 27, 2020 543 544 545 546 547 548 549  if (!(CheckSelfPermission(readPermission) == (int)Permission.Granted) || !(CheckSelfPermission(writePermission) == (int)Permission.Granted)) { RequestPermissions(StoragePermissions, RequestStorageId); } else { ShowMap();  Ryan Duan committed Apr 27, 2020 550  }  Ryan Duan committed Apr 27, 2020 551 }  Ryan Duan committed Apr 27, 2020 552   Kyle Day committed Apr 03, 2020 553   David Rehagen committed Apr 29, 2020 554 Add the following code to the OnRequestPermissionsResult method in the MainActivity.cs:  Kyle Day committed Apr 03, 2020 555   Ryan Duan committed Apr 27, 2020 556 csharp  Ryan Duan committed Apr 27, 2020 557 558 559 public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Permission[] grantResults) { switch (requestCode)  Ryan Duan committed Apr 27, 2020 560  {  Ryan Duan committed Apr 27, 2020 561 562 563  case RequestStorageId: { if(grantResults.Length > 0 && grantResults[0] == Permission.Granted)  Ryan Duan committed Apr 27, 2020 564  {  Ryan Duan committed Apr 27, 2020 565  ShowMap();  Ryan Duan committed Apr 27, 2020 566  }  Ryan Duan committed Apr 27, 2020 567 568 569 570 571 572 573  else { Toast.MakeText(this, "Storage Permissions Denied", ToastLength.Short).Show(); } } break;  Ryan Duan committed Apr 27, 2020 574  }  Ryan Duan committed Apr 27, 2020 575 }  Ryan Duan committed Apr 27, 2020 576   Kyle Day committed Apr 03, 2020 577   Ryan Duan committed Apr 27, 2020 578 Finally, replace the ShowMap call in the OnCreate method with a call to the RequestRequiredPermissions method:  Kyle Day committed Apr 03, 2020 579   Ryan Duan committed Apr 27, 2020 580 csharp  Ryan Duan committed Apr 27, 2020 581 582 // Replace 'ShowMap()' in the 'OnCreate' method RequestRequiredPermissions();  Ryan Duan committed Apr 27, 2020 583   Kyle Day committed Apr 03, 2020 584   David Rehagen committed Apr 29, 2020 585 ### Step 9: Adding an External Data Source - Importing Data  Kyle Day committed Apr 03, 2020 586   Kyle Day committed Sep 10, 2020 587 Now that we have storage permissions set up, we can store the data locally on the Android device. Create a new folder named SampleData under the Assets folder in the solution, then add the map data to it. Make sure the resources� build action is AndroidAsset.  Kyle Day committed Apr 03, 2020 588   Ryan Duan committed Apr 27, 2020 589 Now, we can add a method to copy the data to the external storage for the application to use.  Kyle Day committed Apr 03, 2020 590   Ryan Duan committed Apr 27, 2020 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 csharp private void CopySampleData(string targetDirectory) { if (!Directory.Exists(targetDirectory)) Directory.CreateDirectory(targetDirectory); foreach (string filename in Assets.List("SampleData")) { string sourcePathFilename = Path.Combine("SampleData", filename); string targetPathFilename = Path.Combine(targetDirectory, filename); if (!File.Exists(targetPathFilename)) { string targetPath = Path.GetDirectoryName(targetPathFilename); if (!Directory.Exists(targetPath)) Directory.CreateDirectory(targetPath); Stream sourceStream = Assets.Open(sourcePathFilename); FileStream fileStream = File.Create(targetPathFilename); sourceStream.CopyTo(fileStream); fileStream.Close(); sourceStream.Close(); } }  Kyle Day committed Apr 03, 2020 611 }  Kyle Day committed Apr 03, 2020 612   Kyle Day committed Apr 03, 2020 613   Ryan Duan committed Apr 27, 2020 614 Now we can call this method when we initialize our map, in the ShowMap method.  Kyle Day committed Apr 03, 2020 615   Kyle Day committed Apr 03, 2020 616 csharp  Ryan Duan committed Apr 27, 2020 617 618 619 620 621 622 623 public void ShowMap() { // Set our view from the "main" layout resource SetContentView(Resource.Layout.activity_main); // Copy the required Shapefiles to Device. string targetDirectory = Path.Combine(Environment.ExternalStorageDirectory.ToString(), "SampleData"); CopySampleData(targetDirectory);  Ryan Duan committed Apr 27, 2020 624   Kyle Day committed Apr 03, 2020 625   Ryan Duan committed Apr 27, 2020 626 This method will copy data to the target path, if the folder does not exist.  Kyle Day committed Apr 03, 2020 627   David Rehagen committed Apr 29, 2020 628 ### Step 10: Add a Point Data Layer  Kyle Day committed Apr 03, 2020 629   Ryan Duan committed Apr 27, 2020 630 Now we can add the data from the shapefile to the map, in the ShowMap() method:  Kyle Day committed Apr 03, 2020 631   Ryan Duan committed Apr 27, 2020 632 csharp  Ryan Duan committed Apr 27, 2020 633 634 // Add a shapefile layer with point style. var capitalLayer = new ShapeFileFeatureLayer(Path.Combine(Environment.ExternalStorageDirectory.ToString(), @"SampleData/WorldCapitals.shp"));  Kyle Day committed Apr 03, 2020 635   Ryan Duan committed Apr 27, 2020 636 637 638 639 // Create an overlay to add the layer to and add that overlay to the map. var customDataOverlay = new LayerOverlay(); customDataOverlay.Layers.Add(capitalLayer); androidMap.Overlays.Add(customDataOverlay);  Ryan Duan committed Apr 27, 2020 640   Kyle Day committed Apr 03, 2020 641   David Rehagen committed Apr 29, 2020 642 ### Step 11: Styling and Labeling the Data  Kyle Day committed Apr 03, 2020 643   Ryan Duan committed Apr 27, 2020 644 We won't be able to see the points until a style is defined for it. Adding a style is very straightforward, but extremely extensible and powerful.  Kyle Day committed Apr 03, 2020 645   Ryan Duan committed Apr 27, 2020 646 csharp  Ryan Duan committed Apr 27, 2020 647 648 649 650 651 652 653 654 655 656 var capitalStyle = new PointStyle() { SymbolType = PointSymbolType.Circle, SymbolSize = 8, FillBrush = new GeoSolidBrush(GeoColors.White), OutlinePen = new GeoPen(GeoColors.Black, 2) }; capitalLayer.ZoomLevelSet.ZoomLevel01.DefaultPointStyle = capitalStyle; capitalLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;  Kyle Day committed Apr 03, 2020 657   Kyle Day committed Apr 03, 2020 658   David Rehagen committed Apr 29, 2020 659 ### Step 12: Reprojecting the Data  Kyle Day committed Apr 03, 2020 660   Ryan Duan committed Apr 27, 2020 661 If you run the app now, you'll notice that there is just a single point shape in the center of the map! This is because the data is in a completely different projection from the map. We can easily fix that, though, by adding a ProjectionConverter to the layer from Decimal Degrees(4326) to Spherical Mercator(3857).  Kyle Day committed Apr 03, 2020 662   Kyle Day committed Apr 03, 2020 663 csharp  Ryan Duan committed Apr 27, 2020 664 665 // Set the projection of the capitalLayer to Spherical Mercator capitalLayer.FeatureSource.ProjectionConverter = new ProjectionConverter(4326, 3857);  Ryan Duan committed Apr 27, 2020 666   Kyle Day committed Apr 03, 2020 667   Ryan Duan committed Apr 27, 2020 668 Now, the data shows up properly on the map!  Kyle Day committed Apr 03, 2020 669   David Rehagen committed Apr 29, 2020 670 ### Step 13: Zoom Into the Data  Kyle Day committed Apr 03, 2020 671   Ryan Duan committed Apr 27, 2020 672 Now, we can make the map zoom into an area based on the extent of the data we added above. In order to do that, we must first open the layer for spatial queries to be made.  Kyle Day committed Apr 03, 2020 673   Ryan Duan committed Apr 27, 2020 674 csharp  Ryan Duan committed Apr 27, 2020 675 676 677 // Open capitalLayer for it to be ready for spatial queries. Then, set the extent of the map to the full view of the data. capitalLayer.Open(); mapView.CurrentExtent = capitalLayer.GetBoundingBox();  Kyle Day committed Apr 03, 2020 678   Kyle Day committed Apr 03, 2020 679   David Rehagen committed Apr 29, 2020 680 ### Android Summary  Kyle Day committed Apr 03, 2020 681   Ryan Duan committed Apr 27, 2020 682 You now know the basics of using the ThinkGeo Map controls and are able to get started adding functionality into your own applications. Let's recap what we have learned about the object relationships and how the pieces of ThinkGeo UI work together:  Kyle Day committed Apr 03, 2020 683   Ryan Duan committed Apr 27, 2020 684 685 686 687 688 1. It is of the utmost importance that the units (feet, meters, decimal degrees, etc.) be set properly for the Map control based on the data. 1. FeatureLayers provide the data used by a Map control to render a map. 1. A Map is the basic control that contains all of the other objects that are used to tell how the map is to be rendered. 1. A Map has many layers. A Layer correlates one-to-one with a single data source and typically of one type (point, polygon, line etc). 1. A FeatureLayer can have several ZoomLevels. ZoomLevels help to define ranges (upper and lower) of when a Layer should be shown or hidden.  Kyle Day committed Apr 03, 2020 689   Ryan Duan committed May 11, 2020 690 You are now in a great position to look over the [other samples available](https://gitlab.com/thinkgeo/public/thinkgeo-mobile-maps/-/tree/master/samples/android) and explore our other features.  Kyle Day committed Apr 03, 2020 691   David Rehagen committed Apr 29, 2020 692 ## Need Help?  Kyle Day committed Apr 03, 2020 693   David Rehagen committed Apr 29, 2020 694 If you run into any issues with running the samples, please let us know in the [Community Forums](https://community.thinkgeo.com).  David Rehagen committed Feb 27, 2020 695   Kyle Day committed Apr 03, 2020 696 If you have any questions about the product or sales, please contact us at [sales@thinkgeo.com](mailto:sales@thinkgeo.com).