6 Dec 2019

Fast track your React native Forge App with the Expo SDK - Part II

In the first part of this two episode series we walked through the basics of building cross platform Viewer alps with the Expo SDK. Today we are taking a closer look at this sample project I put together to get us started in minutes: https://github.com/dukedhx/viewer-expo-react-native/


Just to set the standards right from the start - we are still going with H5 and WebView to embed Viewer as there’s no native Viewer SDK available just yet:



If you plan to go with a light footprint and load Viewer and models from a URL or Forge then simply spin up a plain old WebView with minimal fuss:

source={{ uri: 'https://dukedhx.github.io/viewer-expo-react-native/?svfUrl=' + encodeURIComponent(svfUrl)}}

However with this approach we’d got to host the Viewer web app along with the model resources ourselves and bandwidth - although we can save a lot traffic and load times by caching them with Service Worker and Cache APIs. What if we want to load the Viewer app and models within our project?

Starting from recent versions of React Native we will need to load the web apps and models as project assets - doing so is a bit counterintuitive as we need to download the assets and feed the HTML . Be sure to enclose all your styling and scrips in the content string or load them from a URL:

const html = Asset.fromModule(require('./assets/viewer.html'))
html.downloadAsync().then(async () => this.setState({ html: (await FileSystem.readAsStringAsync(html.localUri)) }))

Since Viewer v6+ requires cookie (or precisely its “i18n” requests it) be sure to specify a base URL otherwise cookies would get disabled (cookie lives in domains):

source={{html:this.state.html,baseUrl: "url"}}

Now let’s load the models! Since we can exactly override the request handler (like we could for native stacks explained here) with Expo we will need to resort to WebView messaging - encode the binary as base64 string and pass to our Service Worker intercepting Viewer’s load requests to fulfill the request with decoded contents:

onMessage={event => {

            const path = event.nativeEvent.data

            if (path.startsWith('assets/')) {

              const prefix = 'data://' + new String(path.length).padStart(3, '0') + path      //arbitrary prefix to identify the binary string

              if (modelAssets[path]) {

                const asset = Asset.fromModule(modelAssets[path])

                asset.downloadAsync().then(async () => this.webView.postMessage(prefix + await FileSystem.readAsStringAsync(asset.localUri, { encoding: 'base64' })))
              } else this.webView.postMessage(prefix)

//service- worker.js
self.addEventListener('fetch', event => {


    async function () {

      const url = new URL(event.request.url)

      const groups = url.pathname.match(/^*\/*(.+*\/*)?(assets*\/*.*)/)

      const path = groups ? groups[2] : null

      if (url.host==location.host&&path) {

        (await clients.get(event.clientId)).postMessage({ path })

        const stream = new ReadableStream({

          start (controller) {

            controllers[path] = controller



        return new Response(stream)

      } else return fetch(event.request)



You may extend the above by implementing buffering in chunks and caching to put the cherry on top.

However as of now Service Worker still does not work (it requires entitlement that is not available yet) in a WKWebView and that means we will need to stick with loading from URLs for iOS...

Remember we mentioned the need to “download” the project assets and that implies those resources are persisted to a web location instead of being bundled with the app? Indeed they are - Each time you publish your app, Expo will upload your assets to Amazon CloudFront, a blazing fast CDN. It does this in an intelligent way to ensure your deploys remain fast with small footprints - see more details here.

And read on here and here about building to different platforms and app distribution.

Okay donkey - that’s all we have time for now... Take care and see you around soon!

Related Article

Posted By

Bryan Huang

Bryan Huang is a Developer Advocate with Autodesk Developer Network and is a certified AWS/Azure Solutions Architect/Developer and VMware Practitioner