Apple Maps in FileMaker With MapKit JS

For awhile we’ve been asked: “Can you use Apple Maps inside FileMaker, rather than using Google Maps or MapQuest?” We decided to give it a shot, thanks to MapKit JS, the JavaScript implementation of the MapKit library widely used on macOS and iOS. Here is a technique our FileMaker and JavaScript development teams designed to enable Apple Maps inside a FileMaker solution.

Mapping options inside FileMaker

Many developers are familiar with using web viewers to display a map inside FileMaker, rather than in a separate web browser window or opening the Maps app. MapQuest is particularly easy to use with a web viewer, as FileMaker has built-in support and MapQuest includes a content identifier specifically for FileMaker implementations. Support for Google Maps is also built into FileMaker, though it takes a little more effort to hide the drawer on the left by embedding the map in an Inline Frame (iframe) tag. Apple Maps is more complicated, as at this time it does not support any sort of URL-based scheme.

Enter MapKit JS

We’ve been comfortable with using JavaScript for web viewer functionality inside FileMaker since the technique was first defined. And ever since Apple announced the beta availability of MapKit JS at this year’s Apple Worldwide Developers Conference (WWDC), we were excited to test it out with FileMaker. Just remember, Apple still considers MapKit JS to be “beta”, and it may be subject to modifications with implementation.

Here’s our approach to combining web viewers and MapKit JS in order to use Apple Maps inside FileMaker:

Account Setup

If you do not already have an Apple Developer account, you must first create one before proceeding. Once you have an account, you must complete three steps before working with maps themselves.

  1. Create a Maps ID.
    For organization, reference, and billing, you may want a different ID for each client or solution.
    For the identifier, Apple recommends reverse-DNS–style naming, as in maps.net.beezwax.
  2. Obtain a Maps Private Key.
    Using your ADP account, request a private key paired to the Maps ID and download the resulting file.
  3. Generate a JSON Web Token.
    Finally, use jwt.io and the private key to generate a JSON Web Token (JWT), which you’ll use to authenticate calls to Apple’s API.

Apple provides instructions for completing these setup steps.

Implementation: JavaScript

As noted above, you must have a JSON Web Token to query the MapKit JS API. There are many ways to do that, but we used Node.js 8.11.4.

Save the following code and update with your own team ID, key ID, and private key. Install Node and, in Terminal, enter node <filename.js> .

const jwt = require("jsonwebtoken"); // For generating the JWT and signing it
const privateKey = `
-----BEGIN PRIVATE KEY-----
<Insert entire private key contents here, which is given to you in a *.p8 file for the first time when you create a new Map ID under "Maps IDs"
https://developer.apple.com/account/ios/identifier/mapsId >
-----END PRIVATE KEY-----
`;
const teamId = '<10-character alphanumeric teamId, found at https://developer.apple.com/account/#/membership >';
const keyId = '<10-character alphanumeric map key ID, found under "All Keys" on the left side of https://developer.apple.com/account/ios/certificate/ >';

const payload = {
  iss: teamId /* Issuer: Your Apple Developer Team ID */,
  iat: Date.now() / 1000 /* Issued at: Current time in seconds */,
  exp: Date.now() / 1000 + 315360000 /* Expiration: Time to expire in seconds. This one is set to expire in 10 years. */
};

const header = {
  kid: keyId /* Key Id: Your MapKit JS Key ID */,
  typ: "JWT",
  alg: "ES256"
};

let token = jwt.sign(payload, privateKey, { header });
console.log(token);

This should output a string representing the JWT. Copy this into the client-side JavaScript that initializes MapKit JS:

mapkit.init({
  authorizationCallback: done => {
    done(
      "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
    );
  }
});

var map = new mapkit.Map("map"); // Renders Maps onto an element with the div ID of 'map' on your HTML page.

Now you can begin using the MapKit JS API.

Implementation: FileMaker

This is the easy part. Create a few fields for address, search string, or whatever you need for your implementation; add a web viewer to a layout; and integrate the JavaScript.

  1. For example, the demo file has a field “StartLocation”, which we’ve inserted into the JavaScript code as:
    “const FileMakerQuery = ‘” & Substitute ( Apple Maps::StartLocation ; ¶ ; “, ” ) & “‘;” & ¶ &
    Note the Substitute() function to replace carriage returns, which Apple Maps does not like, with commas, which it prefers.
  2. Next, add a web viewer to the layout. Give it an object name so you can reference it in the CSS for dynamic sizing:
    " #map {" & ¶ & 
    " width: " & GetLayoutObjectAttribute ( "map" ; "width" ) & "px;" & ¶ & 
    " height: " & GetLayoutObjectAttribute ( "map" ; "height" ) & "px;" & ¶ & 
    " }" & ¶ & 
    
  3. We also factor out the token to a global field, which makes it easier to secure and replace when needed.
    " mapkit.init({" & ¶ & 
    " authorizationCallback: done => {" & ¶ & 
    " done(" & ¶ & 
    " '" & Apple Maps::Token & "'" & ¶ & 
    " ); & ¶ & 
    " }" & ¶ & 
    "    });" & ¶ &
  4. Finally, to make long scripts somewhat more readable, we prefix each line with   and suffix with ” & ¶ &  . A tool like BBEdit makes this quick and easy. Also note you’ll either need to use single quotes in your HTML and JavaScript, or escape double quotes. These tweaks allow us to see the script in a more-or-less natural format while still being a valid FileMaker calculation.

Customization

The MapKit JS documentation provides details on the vast array of customization options available when using this library.

Here are two examples to get you started:

  • Search for a query, such as “coffee shops”.
  • Lookup an address to get geographic coordinates.

Since it is still in beta, the MapKit JS documentation is limited. There are few examples of how to use constructors, properties, and functions. You should become comfortable using console.log to output objects to your browser console.

var map = new mapkit.Map("map");
console.log(map);
var coordinate = new mapkit.Coordinate(37.415, -122.048333);
var span = new mapkit.CoordinateSpan(.016, .016);
var region = new mapkit.CoordinateRegion(coordinate, span);
console.log(region);

Demo

We’ve built a simple demo file as a proof-of-concept. It is not meant to illustrate the full range of what is possible, but is, we think, a unique way of looking at map data: Given starting and ending points, highlight all locations along the way that fit our search. Our sample data is an all-important “good coffee finder”, but you could just as easily plot restaurants, gas stations, or “world’s largest object” tourist traps.

Download example file (.zip)

Note this demo is using a Beezwax token, which you’ll want to replace with your own. While beta MapKit JS is largely free, there is a daily API call allotment limit. If API calls exceed the daily allotment or the beta period has ended, this demo may no longer work without replacing the token with one of your own.

Known Issues

We ran into minor problems while experimenting with this technique.

  • When opening a window, the web viewer does not load entirely. Our solution was to apply an OnWindowOpen script trigger. Even though the script can be empty, it seems to be enough to cause the web viewer to draw its content.
  • The web viewer map on iOS sometimes loses the ability to interpret gestures such as scroll, zoom, and rotate. Switching to a different record seems to resolve the issue most of the time, but additional troubleshooting would be necessary for a production solution.
  • The CDN copy of the library uses a relative URL to display the Apple logo in the lower left corner, which does not work when using the file: protocol— way FileMaker web viewers render local code. Our solution, which we included in the demo file, was to modify and store a local copy of the library that uses an absolute URL. Note this local copy will not receive any bug fixes or updates Apple pushes to the CDN.

Final Notes

Path of Travel Closed sign
While we designed this technique for FileMaker Pro Advanced on macOS and FileMaker Go on iOS, it does not work with FileMaker Pro on Windows. FileMaker Pro on Windows uses Internet Explorer as the web viewer rendering engine, and Internet Explorer explicitly prohibits running local JavaScript, around which this technique is based.

About This Article

Hiroshi Usui developed the JavaScript integration with FileMaker to enable MapKit JS and the Apple Maps example provided. Christopher Edwards architected, documented, and tested the FileMaker solution demo. Major credit goes to Brian Schick and Ryan Simms (among others) who pioneered JavaScript-in-FileMaker-Web-Viewer techniques, as well as to Mekuria Getinet for UX Design, and to fellow Beez who have helped test the examples provided here.

Leave a Reply