Categories
Android

How to create and use Offline Maps with an Android App?

When building an app we know is going to be used in areas with no wifi or cellular networks nearby or when we want to offer an offline map option we make use of Offline maps.
Otherwise it would be easier to implement the Android Google Map API.

Maps are made up of a collection of images often referred to as tiles. There are sets of tiles for each zoom level. So the first step in creating an offline map is selecting the area and zoom level to create the tiles.

Creating the Offline Map Tiles

We make use of the Mobile Atlas Creator.

  1. Download and extract the files

  2. Run the application with the .exe or the .sh script. Make sure that suitable permissions (execute) is given to the file.

  3. Use the right click to navigate around the map. Use the right mouse button to select an area.

  4. Make sure the MapSource is set to OpenStreetMap MapQuest. You can try others but the one that works for me is OpenStreetMap MapQuest.

  5. Make sure the Atlas Format is Osmdroid ZIP.

  6. Select the Zoom Levels less will make the file size smaller. Select Recreate/adjust map tiles, PNG and leave the size as deafult. Note: It has to be PNG, JPEGs won’t work on Android

  7. Name the selection and click Add Selection.

  8. Then Create Atlas

    Adding the Offline Map Tiles to your Android Project

    The Map tiles folder or .zip needs to be named specifically and placed in the correct location.

  9. Rename the zip to my_map_name.zip.

  10. Rename the folder in the zip to MapquestOSM. Take note of the spelling and case.

  11. Place the my_map_name.zip file into app/src/main/assets

    Copying the Map Files to the SD Card

    We need to copy the Map Tiles to the SD Card (External Storage) on the Android Device.

  12. Add a function preferably in the application class to make sure the file is copied across to the device.

    
    public static void copyTilestoSDCard(){
    //save zip to sd
    AssetManager am = BaseApp.getmContext().getAssets();
    InputStream is;
    //zip file in assets root
    String sourceFileName = "mp_map_name.zip";
    //zip file in SD card
    String destinationFileName = "tiles.zip";
    String osmDirName = "osmdroid";
    

File osmDir = new File(Environment.getExternalStorageDirectory() + File.separator + osmDirName);

if (!osmDir.exists()){ osmDir.mkdir(); } String filePath = Environment.getExternalStorageDirectory() + File.separator + osmDirName + File.separator + destinationFileName; File destFile = new File(filePath); if (!destFile.exists()){ //file doesn't exist try { is = am.open(sourceFileName); FileOutputStream fo = new FileOutputStream(filePath);

byte[] b = new byte[1024]; int length; while ((length = is.read(b)) != -1){ fo.write(b, 0, length); } fo.flush(); fo.close(); is.close(); } catch (IOException e) { e.printStackTrace(); } } }

Setting Required Permissions for the Offline Map

 <uses-permission android:name="android.permission.INTERNET"/>
 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
 <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
 <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
 <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

Add Open Street Maps Droid with Gradle

You need the OSMDroid, you can add to gradle with:

compile 'org.osmdroid:osmdroid-android:4.2'
compile 'org.slf4j:slf4j-simple:1.6.1'

Now to Display the Offline Map on the Android Device

To display in the app make sure your layout file contains:

<org.osmdroid.views.MapView
    android:id="@+id/offlineMapView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:visibility="gone"
    android:clickable="true"
    android:enabled="true"
    android:layout_alignParentTop="true"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="true"
    />

The controller Fragment or Activity should then intialise the map:


org.osmdroid.views.MapView mOfflineMapView = findById(R.id.offlineMapView);
//Make sure you don't get the map from online
mOfflineMapView.setUseDataConnection(false);
//Set the Tile Source (That is MapqueueOSM)
mOfflineMapView.setTileSource(TileSourceFactory.MAPQUESTOSM);

Then set all your required settings for the MapView:


setMultiTouchControls();
setClickable();
getController().setZoom();
getController().setCenter();

And there we go.

Sources: