适用于iOS的离线MapKit解决方案 [英] Offline MapKit solution for iOS

查看:103
本文介绍了适用于iOS的离线MapKit解决方案的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

快速提问。我有一个我正在研究的应用程序需要使用地图,但不会有网络连接。我见过其他人就此问过类似的问题,但我的要求略有不同,所以我想发一个新问题。

Quick question for you. I have an app that I'm working on that will require the use of maps, but will not have a network connection. I have seen others ask similar questions about this, but my requirements are a slight bit different, so I wanted to post a new question.

以下是我对该应用的要求。

Here are my requirements for the app.


  1. 允许捏合/缩放带有可定义注释的地图

  2. 地图必须离线使用

  3. 地图应限制在某个地理区域

  4. App不必通过Apple检查。这是一个企业应用程序,将作为自助服务终端。

  1. Allow pinch/zoom of a map with definable annotations
  2. Map must be available offline
  3. Map should be restricted to a certain geo area
  4. App does not have to pass Apple inspection. This is an enterprise app that will serve as a kiosk.

那么,是否存在任何人都可以建议的缓存地图图块的框架或方法?

So, is there any framework or method of caching map tiles that anyone can suggest?

谢谢你提前出去。

推荐答案

我使用MapKit的默认地图和MKTileOverlay的子类能够保存下载的图块并返回已经缓存的图块而不下载它们。

I used default map from MapKit and a subclass of MKTileOverlay to be able to save downloaded tiles and return already cached tiles without downloading them.

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

1) Change source for your default map from MapKit and use a subclass of MKTileOverlay (Used "open street map" here)

- (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的子类

2) subclass from 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是一个隐藏目录)

Uncomment "saveFileWithName" and run it on simulator. You can also add NSLog(fileName) to know where to get all tiles you need. (Simulator cache is in Users/YOU/Library/Developer/CoreSimulator/Devices/... And Library is a hidden directory)

缓存后你只需要放入在你的应用程序包中(就像任何其他图像一样,如果你想从盒子缓存的地图)。并告诉你

After you cached all you need just put in your app's bundle (just like an any other image, if you want from box cached map). And tell your

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

从包中获取切片。

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

So now I can install my app, turn wi-fi off and I'll get those maps anyway.

这篇关于适用于iOS的离线MapKit解决方案的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆