Solução para aplicativo de mapa Android com uso offline?

14

Estou em busca de uma maneira de desenvolver um aplicativo para Android com mapas incorporados que possam funcionar sem uma conexão com a Internet (ou seja, posso obter os blocos do mapa de ruas aberto para uso offline?).

Eu desenvolvi aplicativos da web antes usando o google maps api v3. Eu preciso de uma resposta geral como específica. Estou tentando encontrar os conceitos e tecnologias que preciso aprender :)

(Enquanto isso, encontrei o osmdroid. Funciona offline?)

Argiropoulos Stavros
fonte
Isso realmente não responde à pergunta. Se você tiver uma pergunta diferente, faça-a clicando em Fazer pergunta . Você também pode adicionar uma recompensa para chamar mais atenção para essa pergunta quando tiver reputação suficiente .
Jason Scheirer
O Osmand não permite importar mapas personalizados conforme o desejo do usuário, mas apenas permite o download de mapas diretamente do aplicativo para uso offline. Como no meu caso, preciso sobrepor toposheets (mapas de varredura) que foram convertidos em * .kmz. Minha exigência é para uso offline. Estou procurando uma orientação adequada para desenvolver esse aplicativo Android de suporte a mapas offline.
surap
Isso realmente não responde à pergunta original de onde e como obter mapas para uso offline.
MaryBeth
Isso realmente não responde à pergunta. Se você tiver uma pergunta diferente, faça-a clicando em Fazer pergunta . Você também pode adicionar uma recompensa para chamar mais atenção para essa pergunta quando tiver reputação suficiente . - Do comentário
John Powell

Respostas:

13

Fiz um mapa offline usando o ESRI Android SDK e uma camada de mosaico personalizada. Eu usei um servidor ArcGIS para gerar um cache de mapa baseado em bloco, depois inseri esses blocos em um banco de dados SQLite e os consulte com base na linha e coluna a partir daí. Funciona muito bem e, se você precisar de mapas personalizados de ponta a ponta, é um método muito útil.

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;   
}

}

eptilioma
fonte
Você pode compartilhar algum código?
gregm
Eu adicionei minha classe de camada personalizada que faz o trabalho.
eptiliom
7

Eu desenvolvi um aplicativo com mapas offline para Android. A única ferramenta gratuita que você gostaria de usar é o OSMDroid, caso contrário, o ESRI. A API do OSMDroid é idêntica à do Google; portanto, caso você queira mudar de um para outro, é fácil.

Confira este post , com uma amostra de como integrar o Google Maps ao OSMDroid (ele também fornece uma idéia de como usá-lo em geral).

Elijah Saounkine
fonte
2

Existe um ótimo aplicativo chamado xGPS para iPhone e outros dispositivos. Você pode analisar isso para obter idéias, pois permite que os usuários pré-armazenem em cache os mapas necessários. Eu uso quando estou no meio do mato na África, Everglades da Flórida, passeios de barco ou em qualquer lugar onde não tenho cobertura por telefone celular. Vou armazenar os mapas em cache antes da minha viagem e, em seguida, posso usar o GPS no meu iphone normalmente sem INTERNET.

Basicamente, o que o xGPS faz e o que você gostaria de fazer é armazenar em cache os blocos de mapa localmente no seu telefone. O espaço nesses celulares é limitado. Sim, mesmo se você tiver 32 GB no telefone, pode ser o suficiente para armazenar em cache um país pequeno em todos os níveis de zoom (escalas). Nenhum desses telefones (a menos que esteja de alguma forma conectado ao armazenamento externo) terá espaço suficiente para armazenar em cache o mundo em todos os níveis de zoom. Eu imagino que isso exigiria petabytes de armazenamento.

Portanto, você precisa pedir ao usuário para armazenar em cache as "regiões" ou mapas quando ele estiver online, para que ele possa usá-los offline. Com o xGPS, sou capaz de desenhar um polígono sobre minha região de interesse e especificar quais níveis de zoom eu quero armazenar em cache. Em seguida, ele começará a baixar tudo para mim no meu telefone, a partir do próprio telefone ou de um programa no meu computador. Depois, há um botão no aplicativo que permite alternar para o modo "offline" quando eu perder a conectividade com a Internet.

CaptDragon
fonte
2

Tente usar o NextGIS Mobile SDK. O modo online / offline inclui edição e sincronização automática com o servidor (NextGIS Web). Camadas de varredura e vetor, formulários de entrada personalizados, todos os tipos de suporte de geometria.

Um exemplo de aplicativo NextGIS Mobile pode ser encontrado na loja Google Play - https://play.google.com/store/apps/details?id=com.nextgis.mobile

As fontes estão aqui: https://github.com/nextgis/android_gisapp

Documentação: http://docs.nextgis.com/docs_ngmobile/source/toc.html

Outra aplicação simples está aqui: https://github.com/nextgis/android_muni_gisconf

Documentação do SDK: http://docs.nextgis.com/ngmobile_dev/toc.html

Dmitry Baryshnikov
fonte
1

Existe suporte completo para mapas offline com a versão atual do ArcGIS Android SDK. Este exemplo mostra como trabalhar com um pacote de blocos local como um mapa base e persiste os recursos online para os recursos offline, dos quais existem maneiras de editar. Também tenho uma essência disponível no github para uma referência simplificada.

jdONeill
fonte
1

Sugiro dar uma olhada no SDK de mapas 3D da Nutiteq, que possui recursos offline e extras interessantes, como suporte a 3D. Ele é fabricado por uma empresa especializada em desenvolvimento, por isso, oferece suporte comercial dedicado e mais flexibilidade do que os grandes fornecedores fornecem. Disclaimer: Eu sou desenvolvedor dele.

JaakL
fonte