Offline MapKit решение для iOS

Быстрый вопрос для вас. У меня есть приложение, над которым я работаю, это потребует использования карт, но не будет сетевого подключения. Я видел, как другие задавали подобные вопросы по этому поводу, но мои требования немного разные, поэтому я хотел опубликовать новый вопрос.

Вот мои требования к приложению.

  • Разрешить щепотку/масштабирование карты с определяемыми аннотациями
  • Карта должна быть доступна в автономном режиме
  • Карта должна быть ограничена определенной географической областью
  • Приложению не нужно проходить проверку Apple. Это корпоративное приложение, которое будет служить киоском.

Итак, есть ли какой-либо каркас или метод кэширования карточных плит, которые могут предложить любой?

Благодарим вас заблаговременно.

Ответ 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 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 (имя_файла), чтобы узнать, где получить все необходимые вам плитки. (Кэш симулятора находится в разделе "Пользователи/YOU/Library/Разработчик/CoreSimulator/Devices/... И Library - скрытая директория)

После того, как вы кэшировали все, что вам нужно, просто добавьте в свой комплект приложений (как и любое другое изображение, если хотите, с помощью кеш-карты). И скажите

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

чтобы получить фрагменты из пакета.

Итак, теперь я могу установить свое приложение, отключить Wi-Fi, и все равно получаю эти карты.

Ответ 2

Попробуйте использовать http://mapbox.com/, в котором есть как SDK для iOS, так и приложение для создания автономных карт.

Ответ 3

Отметьте раздел 10.3 Условия использования Google Maps, и вы обнаружите, что вам запрещено хранить контент Google Maps. Это означает, что вам необходимо предоставить не только собственную карту, но и заменить удобные функциональные возможности MapKit. Насколько мне известно, вы действительно не можете использовать MapKit для автономных приложений.

Ответ 4

К сожалению, MapKit Framework не поддерживает автономный доступ к карте. Вы должны предпочесть MapBox iOS  SDK (MapBox iOS SDK - это набор инструментов для создания карт приложений, поддерживающих политику автономного кэширования, ограничения масштабирования, поведение отображения сетчатки, начальную координату и замедление тангажа карты и т.д.).

Найдите ссылку примера

Счастливое кодирование

Ответ 5

Смотрите skobbler/Telenav SDK - он основан на OpenStreetMap и является (почти) полной заменой стека на mapkit (рендеринг карты, маршрутизация и пошаговая навигация) со встроенной поддержкой офлайн-карт