【问题标题】:Offline MapKit solution for iOSiOS 离线 MapKit 解决方案
【发布时间】:2015-08-27 17:01:33
【问题描述】:

给你一个快速的问题。我正在开发一个需要使用地图的应用程序,但没有网络连接。我看到其他人对此提出了类似的问题,但我的要求略有不同,所以我想发布一个新问题。

这是我对应用程序的要求。

  1. 允许捏合/缩放带有可定义注释的地图
  2. 地图必须离线可用
  3. 地图应限制在某个地理区域内
  4. 应用程序不必通过苹果检查。这是一个将用作信息亭的企业应用程序。

那么,有没有任何人可以建议的缓存地图图块的框架或方法?

谢谢提前出去。

【问题讨论】:

  • 我担心 Caleb 是对的。即使你能以某种方式缓存地图数据——你也不会使用它。

标签: ios ipad mapkit offline


【解决方案1】:

我使用 MapKit 的默认地图和 MKTileOverlay 的子类来保存下载的切片并返回已缓存的切片而不下载它们。

1) 从 MapKit 更改默认地图的来源并使用 MKTileOverlay 的子类(此处使用“开放街道地图”)

- (void)viewDidLoad{
    [super viewDidLoad];
    static NSString * const template = @"http://tile.openstreetmap.org/{z}/{x}/{y}.png";

    VHTileOverlay *overlay = [[VHTileOverlay alloc] initWithURLTemplate:template];
    overlay.canReplaceMapContent = YES;
    [self.mapView addOverlay:overlay level:MKOverlayLevelAboveLabels];
}

2) MKTileOverlay 的子类

@interface VHTileOverlay() // MKTileOverlay subclass
@property (nonatomic, strong) NSOperationQueue *operationQueue;
@end

@implementation VHTileOverlay

-(instancetype)initWithURLTemplate:(NSString *)URLTemplate{

    self = [super initWithURLTemplate:URLTemplate];
    if(self){
        self.directoryPath = cachePath;
        self.operationQueue = [NSOperationQueue new];
    }
    return self;
}


-(NSURL *)URLForTilePath:(MKTileOverlayPath)path {
    return [NSURL URLWithString:[NSString stringWithFormat:@"http://tile.openstreetmap.org/%ld/%ld/%ld.png", (long)path.z, (long)path.x, (long)path.y]];
}

-(void)loadTileAtPath:(MKTileOverlayPath)path
                result:(void (^)(NSData *data, NSError *error))result
{
    if (!result) {
        return;
    }

    NSString *pathToFilfe = [[self URLForTilePath:path] absoluteString];
    pathToFilfe = [pathToFilfe stringByReplacingOccurrencesOfString:@"/" withString:@"|"];
    // @"/" - those are not approriate for file's url...

    NSData *cachedData = [self loadFileWithName:pathToFilfe]; 
    if (cachedData) {
        result(cachedData, nil);
    } else {
        NSURLRequest *request = [NSURLRequest requestWithURL:[self URLForTilePath:path]];
        __block VHTileOverlay *weakSelf = self;
        [NSURLConnection sendAsynchronousRequest:request
                                           queue:self.operationQueue
                               completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
                                   NSLog(@"%@",[weakSelf URLForTilePath:path]);

                                   if(data){
                                       [self saveFileWithName:[[weakSelf URLForTilePath:path] absoluteString] imageData:data];
                                   }
                                   result(data, connectionError);
        }];
    }
}

-(NSString *)pathToImageWithName:(NSString *)fileName
{
    NSString *imageFilePath = [[OfflineMapCache sharedObject].cachePath stringByAppendingPathComponent:fileName];
    return imageFilePath;
}

- (NSData *)loadFileWithName:(NSString *)fileName
{
    NSString *imagePath = [self pathToImageWithName:fileName];
    NSData *data = [[NSData alloc] initWithContentsOfFile:imagePath];
    return data;
}

- (void)saveFileWithName:(NSString *)fileName imageData:(NSData *)imageData
{
//    fileName = [fileName stringByReplacingOccurrencesOfString:@"/" withString:@"|"];
//    NSString *imagePath = [self pathToImageWithName:fileName];
//    [imageData writeToFile:imagePath atomically:YES];
}

取消注释“saveFileWithName”并在模拟器上运行它。您还可以添加 NSLog(fileName) 以了解从何处获取所需的所有图块。 (模拟器缓存在Users/YOU/Library/Developer/CoreSimulator/Devices/...而Library是一个隐藏目录)

缓存所有内容后,您只需将其放入应用的捆绑包中(就像任何其他图像一样,如果您想从盒子缓存的地图中获取)。并告诉你的

- (void)loadTileAtPath:(MKTileOverlayPath)path
                result:(void (^)(NSData *data, NSError *error))result

从包中获取图块。

所以现在我可以安装我的应用程序,关闭 wi-fi,无论如何我都会得到这些地图。

【讨论】:

  • 我试过用你的代码但是有很多问题,你能不能放一个简单的项目
【解决方案2】:

尝试使用http://mapbox.com/,它既有 iOS SDK 又有用于构建离线地图的应用。

【讨论】:

    【解决方案3】:

    查看Google Maps Terms of Service 的第 10.3 节,您会发现不允许存储任何 Google 地图内容。这意味着您不仅需要提供自己的地图,还需要替换方便的 MapKit 功能。据我所知,你真的不能将 MapKit 用于离线应用程序。

    【讨论】:

      【解决方案4】:

      很遗憾,MapKit 框架不支持离线地图访问。你应该更喜欢 MapBox iOS SDK(MapBox iOS SDK是用于构建地图应用程序的工具集,支持离线缓存策略、缩放限制、视网膜显示行为、起始坐标和地图视图拖动减速等......

      Find the example link

      快乐编码

      【讨论】:

        【解决方案5】:

        查看skobbler/Telenav SDK - 它基于 OpenStreetMap,是 mapkit(地图渲染、路由和转弯导航)的(几乎)全栈替代品,集成了对离线地图的支持

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-04-18
          • 2016-12-22
          • 1970-01-01
          • 2011-12-05
          • 1970-01-01
          • 1970-01-01
          • 2023-01-30
          • 2015-12-16
          相关资源
          最近更新 更多