如何从离线的OpenStreetMap创建地图瓦片,并在Android上显示?

20

我想展示一个使用OpenStreetMap的简单离线地图。但是我在网上找不到正确的工具来创建地图瓦片,并将其用于在Android上显示地图。我已经下载了不同的资源,但似乎不知道从哪里开始。我想使用JOSM集成OpenStreetMap的图像,但不确定是否可以在Android上使用。

我能使用Mapnik吗?谢谢您的帮助。


1
是的,你可以使用Mapnik。但这个问题不适合在这里讨论。你应该去help.openstreetmap.org提问。 - Jonas
我不认为这是离题的,但您在 help.openstreetmap.org 上是正确的,那里可能会有更多的OSM专家。 - youseeus
谢谢您的评论。您还有其他想法可以添加到这个话题吗? - rahstame
我能够显示地图,但需要使用互联网"<uses-permission android:name="android.permission.INTERNET" />"。但是我不想使用它。我的意思是,我想要一个离线工作的项目。我想要以编程方式显示存储在项目文件夹中的地图。它应该是离线的,并且应该能够缩放。请分享您的想法。谢谢Tim先生为我澄清了我的想法。请分享其他想法。 - rahstame
3个回答

27

我目前正在使用OpenStreetMap(OSM)API开发(我的第一个)Android应用程序,因此虽然我无法帮助您解决JSOM问题,但我可以尝试帮助您处理OSM部分:

假设您想在Android应用程序中创建一个新的活动,该活动仅显示一个OSM地图,则可以从以下内容开始:

package example.stackoverflow.osmdroid;

import android.app.Activity;
import android.os.Bundle;

import org.osmdroid.tileprovider.tilesource.TileSourceFactory;
import org.osmdroid.util.GeoPoint;
import org.osmdroid.views.MapView;

public class YourMap extends Activity {
    // The MapView variable:
    private MapView m_mapView;

    // Default map zoom level:
    private int MAP_DEFAULT_ZOOM = 15;

    // Default map Latitude:
    private double MAP_DEFAULT_LATITUDE = 38.535350;

    // Default map Longitude:
    private double MAP_DEFAULT_LONGITUDE = -121.753807;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Specify the XML layout to use:
        setContentView(R.layout.osm_map);

        // Find the MapView controller in that layout:
        m_mapView = (MapView) findViewById(R.id.mapview);

        // Setup the mapView controller:
        m_mapView.setBuiltInZoomControls(true);
        m_mapView.setMultiTouchControls(true);
        m_mapView.setClickable(true);
        m_mapView.setUseDataConnection(false);
        m_mapView.getController().setZoom(MAP_DEFAULT_ZOOM);
        m_mapView.getController().setCenter(
            new GeoPoint(MAP_DEFAULT_LATITUDE, MAP_DEFAULT_LONGITUDE));
        m_mapView.setTileSource(TileSourceFactory.MAPNIK);
    } // end onCreate()
} // end class YourMap

如果您的osm_map.xml布局看起来像这样:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

        <org.osmdroid.views.MapView
            android:id="@+id/mapview"
            android:layout_width="match_parent" 
            android:layout_height="match_parent"
            android:enabled="true"      
            android:clickable="true"
        />  
</RelativeLayout>

关于实际的地图瓦片,有一个非常酷的程序叫做Mobile Atlas Creator,它允许你为上面实现的离线Android地图生成必要的地图瓦片。

一旦你安装了该应用程序,并且你想创建一个新的地图集,你将被要求选择你的"期望的地图集格式"。当这个窗口弹出时,选择"Osmdroid zip"。

一旦所有内容加载完成,选择地图上的一个区域,选择你想要的瓦片缩放级别,然后点击左侧栏中的"添加选择"按钮,接着点击"创建地图集"。

哦,还有,根据来源的不同,你可能需要勾选"创建/调整地图瓦片"复选框以将瓦片导出为PNG格式 -- 有人知道是否可以在OSM中使用JPG格式吗?

一旦ZIP文件已经生成,我将其重命名为"Mapnik.zip"并将其移动到我Eclipse Android项目工作区中新创建的"tiles"文件夹中。为了使其正常工作,我还需要打开zip文件,将顶层文件夹从类似于"Google Earth"(取决于你使用的地图源)的名称改为"Mapnik",以便在我的Android应用程序中显示瓦片。

但是,为了将瓦片实际加载到你的手机上,你需要使用终端中的ADB工具。在ADB工具目录中,你需要运行类似于以下命令(每个命令换一行):

./adb shell rm -r /sdcard/osmdroid/
./adb shell mkdir /sdcard/osmdroi/
./adb push ~/path/to/your/mapnik.zip /sdcard/osmdroid
根据地图大小和手机内存总线的速度,这一步可能需要几分钟到一小时不等的时间才能完成。完成后,您的地图应该可以正常工作--希望如此!正如我提到的,这是我第一次使用OSM API,所以我对它并不是很了解,我只能评论我成功的经验。希望这可以帮助您入门!
编辑:昨天我没有实际运行编写的代码,所以没能发现其中一些错误。我刚刚在Eclipse中创建了一个新项目,把我的代码倒进去,修正了几个问题,使其能够运行。我做出的所有更改都反映在上面的代码中!我忘记了几个基本的导入语句,并且忘记向manifest.xml文件添加权限。我的manifest.xml的最后几行现在看起来像这样:
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> 
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
</manifest>

而且您可能还想将此添加到清单中,尽管这并不是必要的:

<supports-screens 
    android:anyDensity="true"
    android:resizeable="false"
    android:largeScreens="true"
    android:normalScreens="true"
/>

<uses-sdk ... />部分之后添加以下内容。

此外,请确保导入以下两个JAR库:

osmdroid-android-3.0.3.jar // Or whatever version you're using...

slf4j-android-1.5.8.jar // Or whatever the latest version is...

如果没有这个最后的JAR(Java归档文件),我的代码会一直崩溃,直到我想起要加入它为止。

确保修改默认坐标,以便它们指向您实际拥有地图瓦片的位置,否则除了一个白色画布之外,您将看不到任何东西。

很抱歉我没有先在自己的端上运行该代码!


嗨rahstame,根据您发布的输出,您可能正在尝试包含共享某些相同包和类的两个JAR文件;换句话说,一些包含的JAR文件之间存在冲突。请查看此链接中的建议:https://dev59.com/43E85IYBdhLWcg3wpFEa。 - Tim Severeijns
我按照您的步骤进行了操作:我将您的Java代码复制粘贴到“package com.YourMap;”下,然后我有未使用的导入“import org.osmdroid.tileprovider.tilesource.BitmapTileSourceBase;”,我还有/res/layout/osm_map.xml。然后创建了一个文件夹:/tiles/Mapnik.zip,来自Mobile Altas Creator。 - rahstame
2
https://dev59.com/42HVa4cB1Zd3GeqPoqT1#9749861 - Girish Bhutiya
我按照答案中描述的步骤进行了操作,但是在某个步骤卡住了。“一旦所有内容加载完成,在地图上选择您想要创建瓷砖的区域,选择您想要的缩放级别,然后点击左侧列中的“添加选择”按钮,接着点击“创建地图集”按钮。”当我将“所需地图集格式”选择为“Osmdroid zip”时,它会加载一个户外地图。如何将我使用JOSM创建的室内地图加载到MOBAC中?谢谢! :) - direndd
Diren,你能否澄清一下你所说的室外地图和室内地图的含义?另外,请记住我已经将近两年没有使用OpenStreetMap了,所以我可能无法回答你的问题。 - Tim Severeijns
显示剩余9条评论

6
这里是一步一步的解决方案:
简要概述:
1- 您必须使用Mobile Atlas Creator下载地图瓦片。我已经在这里解释了步骤。
2- 将生成的zip文件移动到设备上的/mnt/sdcard/osmdroid/目录中。
3- 将osmdroid-android-XXX.jarslf4j-android-1.5.8.jar添加到项目的构建路径中。
4- 添加MapView:您可以将MapView添加到xml布局中。
<org.osmdroid.views.MapView
    android:id="@+id/mapview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tilesource="Mapnik"
    />

或者以编程方式创建MapView:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
    mResourceProxy = new ResourceProxyImpl(inflater.getContext().getApplicationContext());
    mMapView = new MapView(inflater.getContext(), 256, mResourceProxy);
    return mMapView;
}

不要忘记在Manifest中添加这些权限:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> 
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

这是一个不错的示例项目。希望对你有所帮助;)
重要提示:
正如@Scai所提到的:最近Open Street Map宣布此工具不好用并存在一些问题:
引用: 此工具会导致OSM瓦片服务器的大量流量,可能会被阻止。 请不要使用它。

请注意,MOBAC对于OSM瓷砖服务器非常不好,您很可能会被阻止。有关更多信息,请参见https://wiki.openstreetmap.org/wiki/MOBAC。 - scai

1

除了使用地图瓦片进行映射,您还可以使用矢量数据创建离线地图,例如Mapsforge或Mapbox Android SDK。有关更多信息,请参阅OSM维基关于离线OSMAndroid库的内容。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接