Situm Map Viewer functionality allows your users to view your venue cartography even if they don’t have internet access at all times. It works as follows: first, our Map Viewer downloads all the needed information (floorplans, POIs, routes…) when it has access to the internet, and after that, it can work fully offline.
If you want to enable offline functionality for the Map Viewer inside your app, you will need to perform certain configurations as described below. Keep reading!
Note: If you are not using the Map Viewer, you might want to take a look at this article how to enable offline for indoor positioning & raw cartography data access.
Android Configuration #
On Android devices, offline (both for positioning & maps) works out of the box, so there is no need for any additional configuration (other than following the general steps recommended in the Quickstart Guides).
iOS Configuration #
As in Android, iOS positioning will work out of the box without any additional configuration (other than following the Quickstart Guides). Offline maps, however, are a bit trickier.
WKAppBoundDomains: specifying Situm’s domain #
The offline functionality for offline maps on iOS relies on AppBoundDomains. To make it work, first of all you need add the key WKAppBoundDomains to your application’s Info.plist
(typically located under the ios/YOUR_APP_NAME/
directory of your app), specifying the underlying MapViewer domain. This domain will most likely be map-viewer.situm.com
(unless you’ve deployed Situm it on your own private cloud).
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> ... <key>WKAppBoundDomains</key> <array> <string>map-viewer.situm.com</string> </array> </dict> </plist>
If you don’t use any other WKWebViews
directly in your app or in any of the libraries your app uses, the configuration ends here. Otherwise, keep reading.
Compatibility with other Web views in your app #
Setting the WKAppBoundDomains
will affect all the Web views that your application uses (e.g. from 3rd party libraries). Therefore, any other WKWebView
s instances in your application will default to a mode where JavaScript injection, custom style sheets, cookie manipulation, and message handler use is denied. Therefore, they will probably stop working if they aren’t configured properly. To solve this, follow these steps
Step 1 – Add all the Web View domain’s to WKAppBoundDomains in Info.plist #
- Add the domain’s that these Web Viewer connect to in your
WKAppBoundDomains
keys (Info.plist). For example, if the Web View connects tohttps://other-domain.com
:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> ... <key>WKAppBoundDomains</key> <array> <string>map-viewer.situm.com</string> <string>other-domain.com</string> </array> </dict> </plist>
After this, you will need to limit the navigation to the configured App Bound Domains.
Step 2 – Limit Navigation to App Bound Domains #
The configuration you need to apply in this step will depend on whether you have control over the creation of the Web Views used by your app (other than Situm’s), or you don’t.
Scenario 1 (simplest): You control the creation of the other Web Views #
If you control the creation of the other webViews used by your application, you are in the simpler scenario, you only need to enable limitsNavigationsToAppBoundDomains
at WKWebView
creation:
WKWebViewConfiguration *conf = [WKWebViewConfiguration new]; if (@available(iOS 14.0, *)) { conf.limitsNavigationsToAppBoundDomains = true; } //Add your own additional configuration self.webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height) configuration:conf];
Scenario 2 (more complex): You don’t control the creation of the other Web Views #
If you don’t have control over the creation of the other webViews used by your application, you’re in a more complex scenario: you will need to enable limitsNavigationsToAppBoundDomains
over a WKWebView
you don’t own.
To achieve this, you will need to extend the WKWebView
class and use a technique called method swizzling. This technique allows you to change the implementation of a method at runtime. Thus, you will swizzle WKWebView
initWithFrame:configuration
method to activate the limitsNavigationsToAppBoundDomains
at WKWebView
initialization.
Objective-C. Swizzling the WKWebView initFrame:configuration #
For Objective-C, follow these steps.
First of all, create a new File From Templat
e and choose Objective C File
. Configure the file as in the following image:

Then, select your target and Create the File
. After that, replace the code in the WKWebView+Swizzling.h
file with:
#import <WebKit/WebKit.h> NS_ASSUME_NONNULL_BEGIN @interface WKWebView (Swizzling) + (void)swizzleInit; @end NS_ASSUME_NONNULL_END
Also, replace the code in the
file with:WKWebView+Swizzling.m
#import "WKWebView+Swizzling.h" #import <objc/runtime.h> @implementation WKWebView (Swizzling) + (void)swizzleInit { SEL originalSelector = @selector(initWithFrame:configuration:); SEL swizzledSelector = @selector(swizzled_initWithFrame:configuration:); Method originalMethod = class_getInstanceMethod([WKWebView class], originalSelector); Method swizzledMethod = class_getInstanceMethod([WKWebView class], swizzledSelector); if (originalMethod && swizzledMethod) { method_exchangeImplementations(originalMethod, swizzledMethod); } } - (instancetype)swizzled_initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration { if (@available(iOS 14.0, *)) { configuration.limitsNavigationsToAppBoundDomains = YES; } else { NSLog(@"WKWebView limitsNavigationsToAppBoundDomains NOT AVAILABLE ON THIS DEVICE."); } // Call the original implementation (now swizzled) return [self swizzled_initWithFrame:frame configuration:configuration]; } @end
Then, in the application:didFinishLaunchingWithOptions:
of your AppDelegate
call [WKWebView swizzleInit]
:
AppDelegate.m #import "WKWebView+Swizzling.h" - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [WKWebView swizzleInit]; //Any other code you need to add return true }
Swift. Swizzling the WKWebView init(frame:configuration:) #
For Swift, follow these steps.
First, create a new class called WKWebViewSwizzling.swift
:
import Foundation import ObjectiveC import WebKit extension WKWebView { static func swizzleInit() { let originalSelector = #selector(WKWebView.init(frame:configuration:)) let swizzledSelector = #selector(swizzled_init(frame:configuration:)) guard let originalMethod = class_getInstanceMethod(WKWebView.self, originalSelector), let swizzledMethod = class_getInstanceMethod(WKWebView.self, swizzledSelector) else { return } method_exchangeImplementations(originalMethod, swizzledMethod) } @objc func swizzled_init(frame: CGRect, configuration: WKWebViewConfiguration) -> WKWebView { if #available(iOS 14.0, *) { configuration.limitsNavigationsToAppBoundDomains = true } else { print("WKWebView limitsNavigationsToAppBoundDomains NOT AVAILABLE ON THIS DEVICE.") } return swizzled_init(frame: frame, configuration: configuration) } }
Then, call WKWebView.swizzleInit()
from application(_:didFinishLaunchingWithOptions:)
of you AppDelegate
:
@UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { WKWebView.swizzleInit() //Any other code you need to add return true }