Take the 2-minute tour ×
Geographic Information Systems Stack Exchange is a question and answer site for cartographers, geographers and GIS professionals. It's 100% free, no registration required.

As the title reveals i'm in search of a way to develop an app for android with embedded maps which can work without an internet connection(i.e. can i get the tiles of the open streetmap for offline use?).

I have developed web apps before by using the google maps api v3. I need a general answer as a specific one.I'm trying to find the concepts and technologies i need to learn :)

(Meanwhile i found osmdroid.Does it work offline?)

Cheers

share|improve this question
    
This does not really answer the question. If you have a different question, you can ask it by clicking Ask Question. You can also add a bounty to draw more attention to this question once you have enough reputation. –  Jason Scheirer Nov 24 '13 at 19:22
add comment

6 Answers

up vote 4 down vote accepted

Are you looking for Development for Mobile/Cell App? as the new Google Tablet comes with Offline Google Maps in vector format rather than raster tiles.

Google Honeycomb (Tablet) has full support of Google Maps Offline (Vector)

http://androidandme.com/2010/12/news/andy-rubin-demos-honeycomb-running-on-a-dual-core-motorola-tablet/

Video at the bottom explains and shows the application.

share|improve this answer
add comment

I have developed an application with offline maps for Android. The only free tool you would want to use is OSMDroid, otherwise ESRI. OSMDroid API is identical to Google's, so in case you want to switch from one to another, it's a breeze.

Check out this post, with a sample of how to integrate Google Maps into OSMDroid (it also gives you an idea how to use it in general).

share|improve this answer
add comment

I did an offline map using the ESRI Android SDK and a custom tile layer. I used an ArcGIS server to generate a tile based map cache, then inserted those tiles into a SQLite database and query them based on row and column from there. It works great and if you need custom maps end to end, it is a very usable method.

package com.main.utilinspect;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.List;

import org.codehaus.jackson.JsonFactory;
import org.codehaus.jackson.JsonParser;

import android.content.Context;
import android.util.Log;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

import com.esri.core.internal.c.d;
import com.esri.core.internal.c.h;
import com.esri.core.internal.c.l;

import com.esri.android.map.TiledServiceLayer;

public class OfflineDbTiledLayer extends TiledServiceLayer {

File workingDirectory;
String mapDefinition;
String databaseName;
private SQLiteDatabase database;
File blankImage;

byte[] blankImageBytes;

private final Object lock = new Object();


private static final String TAG = "OfflineTiledLayer";  


public OfflineDbTiledLayer(Context paramContext, File workingDirectory, String mapDefinition, String databaseName)  {
    super("required");
    this.workingDirectory = workingDirectory;
    this.mapDefinition = mapDefinition;
    this.databaseName = databaseName;

    String databasePath = workingDirectory.getAbsolutePath() + File.separator + databaseName;

    this.database = SQLiteDatabase.openDatabase(databasePath, null, SQLiteDatabase.NO_LOCALIZED_COLLATORS); 

    this.blankImage = new File(workingDirectory.getAbsolutePath() + File.separator + "blank.png");

    RandomAccessFile raFile = null;

    try {
        raFile = new RandomAccessFile(this.blankImage, "r");

        blankImageBytes = new byte[(int) raFile.length()];
        raFile.readFully(blankImageBytes);

    } catch (FileNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }       
    finally {
        if(raFile != null) {
            try {
                raFile.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }   

    h h1 = null;

    try
    {

    JsonParser paramJsonParser = new JsonFactory()
    .createJsonParser(new File(workingDirectory.getAbsolutePath() + File.separator + mapDefinition));
    paramJsonParser.nextToken();    

    h1 = h.a(paramJsonParser, "test");
    }
    catch(Exception ex){

    }       


    setFullExtent(h1.f());      
    setDefaultSpatialReference(h1.c());
    setInitialExtent(h1.e());

    l l1;
    List list;
    int i;
    double ad[] = new double[i = (list = (l1 = h1.d()).h).size()];
    double ad1[] = new double[i];
    for(int j = 0; j < list.size(); j++)
    {
        ad[j] = ((d)list.get(j)).b();
        ad1[j] = ((d)list.get(j)).a();
    }

    setTileInfo(new com.esri.android.map.TiledServiceLayer.TileInfo(l1.f, ad, ad1, i, l1.c, l1.b, l1.a));

    super.initLayer();
    return;     
}   

private void openDatabase(){
    if(!database.isOpen()){
        String databasePath = workingDirectory.getAbsolutePath() + File.separator + databaseName;
        this.database = SQLiteDatabase.openDatabase(databasePath, null, SQLiteDatabase.NO_LOCALIZED_COLLATORS); 
    }
}

private void closeDatabase(){
    if(database.isOpen()){
        this.database.close();
    }
}

@Override
protected byte[] getTile(int level, int column, int row) throws Exception {
    byte[] tileImage;       

    Log.i(TAG, "getTile");

    Log.i(TAG, "getTile - retrieving tile");            

    synchronized(lock) {

        Log.i(TAG, "getTile - entered synchronized block");

        openDatabase();     

        // First check to see if the tile exists in the database
        Cursor tileCursor = database.rawQuery("SELECT image FROM tiles WHERE level = " + Integer.toString(level) + " AND row = " + Integer.toString(row) + " AND column = " + Integer.toString(column), null);

        if(tileCursor != null && tileCursor.getCount() > 0) {
            tileCursor.moveToFirst();
            tileImage = tileCursor.getBlob(0);
            Log.i(TAG, "getTile - tile found, returning image");                        
        }
        else {
            // The tile does not exist in the database, read the blank placeholder tile and serve it
            tileImage = blankImageBytes;
            Log.i(TAG, "getTile - tile not found returning blank");
        }   

        tileCursor.close();     
        this.database.close();
    }

    Log.i(TAG, "getTile - exited synchronized block");

    return tileImage;   
}

}

share|improve this answer
    
Can you please share some code? –  gregm Mar 1 '13 at 19:02
    
I added my custom layer class that does the work. –  eptiliom Mar 5 '13 at 22:06
add comment

There is a great app called xGPS for iPhone and other devices. You might want to look at that to get ideas because it allows users to pre-cache the maps they will need. I use it when i'm deep in the bush in Africa, Florida Everglades, boating, or anywhere i have no cell phone coverage. I will cache the maps before my trip and then can use the GPS on my iphone normally with NO INTERNET.

Basically what they xGPS does and what you would want to do is cache the map tiles locally on your phone. Space on these mobile phones are limited. Yes even if you have 32gb on your phone, it might just be enough to cache a small country on all zoom levels (scales). None of these phones (unless somehow attached to external storage) are going to have enough space to cache the world at all zoom levels. I imagine this would require petabytes of storage.

So you need to be able to ask your user to cache the "regions" or maps when he's online so he can use them offline. With xGPS i'm able to draw a polygon over my region of interest and specify what zoom levels i want to cache. Then it will start downloading it all for me on to my phone, either from the phone itself or a program on my computer. Then there is a button on the app that allows me to switch to "offline" mode when i loose internet connectivity.

share|improve this answer
add comment

I suggest to take a look to Nutiteq 3D maps SDK which has offline capabilities and interesting extras like 3D support. It is made by specialized developer company behind it, so it has dedicated commercial support and more flexibility than big vendors provide. Disclaimer: I'm developer of it.

share|improve this answer
add comment

There is full support for offline maps with the current release of ArcGIS Android SDK. This sample will show you how to work with a local Tile Package as a basemap and persist online features to offline features from which there are ways you can edit. I have a gist available on github as well for a simplified reference.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.