I did some investigation on iOS to understand what types of constraints we are operating under on the platform. I also created a demo application.
The challenge
iOS has restrictions on what can run in the background and for how long. Because of these, we can’t install a Blockstack Core API node that’s always running on iOS like we do on desktop platforms.
The questions
On iOS:
- Can we run a web server? Yes
- Can we access that web server from our own app? Yes
- Can we access that web server from another app? Yes, but only for a limited amount of time.
Demo
We can:
- Start a webserver on an iOS device (to provide Blockstack API and/or the Portal)
- Access that web server for as long as we want through a webview running in our app.
- Access that web server from other applications on the device for a period of time while the app is in the background.
- Keep the server running for a period of time after the app goes into the background. On both my iPhone 7 plus running 10.3 and the iOS simulator bundled with Xcode 8.3, that time is approximately ~175 seconds. It may be significantly less on older devices and can be cut short by the operating system for various reasons. (eg. low memory, low battery)
Some screenshots:
User Interface
In this demo, I am using a SFSafariViewController
. The benefit of this component is that it has access to everything that Safari has access to: the user’s cookies, local storage, etc. The downside (from our perspective) is that we can’t do anything with its interface.
Using WKWebView
would allow us to customize the interface (we could remove the localhost @guylepage3 ) and experience at the expense of losing access to shared cookies, local storage, etc from Safari. We’d only want Blockstack Web Apps running in our app anyways (so that they can always access the Core API), so this is probably an acceptable trade off.
Syncing data with native apps
Since we can’t provide a Blockstack Core API endpoint that’s always available, accessing storage is a challenge for native apps.
Let’s examine different scenarios and some possible approaches:
Storing data when the Blockstack app is running in background
Apps should be able to access the Blockstack API as normal during the time the Blockstack App is active in the background.
Storing data when the Blockstack app is NOT running in the background
I see two approaches to this:
1. Explicit user initiated storage
- Native app redirects the user (using a custom URI scheme handler) to the Blockstack iOS app
- Blockstack iOS app starts the API
- Blockstack iOS send the user back to original app (again using a custom URL scheme handler registered by the app)
- App writes data to the API
2. Background storage
- Native app sends an api request indicating that it would like to save some data to an endpoint run by Blockstack Inc. (Centralization!)
- Endpoint sends a silent Apple Push Notification to the Blockstack iOS app.
- Blockstack iOS app is woken up by iOS when it receives the notification and has a short period of time where it can run in the background (anecdotally ~30 seconds). During this period, it could start the API.
- Native app polls periodically for the Blockstack API to start. When it starts, the app writes data to the API.
This background storage method is predicated on the iOS app having the remote notification and background fetch capabilities:
It also requires users not to disable Background App Refresh.
Background refresh is toggled in Settings -> General -> Background App Refresh
Summary
I think the situation on mobile, at least for iOS, is very positive.
We can offer the full Blockstack experience for web apps as long as we load them in our built-in browser with little change from apps running in desktop browsers.
We can offer native apps most of the Blockstack experience with a bit of additional work required on storage and some constraints on size and the amount of time an app can spend writing its data to the API.
We might even be able to solve the problem of an API that is only periodically available by putting the logic for handling offline (unreachable) storage in our client libraries instead of behind the Core API.
Thoughts Team @Blockstack?