📱 WebApp Integration
API partners can embed the Earth Miles web app directly into their applications using a WebView. This allows users to interact with Earth Miles without leaving your app.
Prerequisites
Before integrating the web app, ensure you have:
- Completed the OAuth integration to connect users
- Your unique Membership ID (provided by Earth Miles)
Integration Steps
1. Connect the User
First, complete the OAuth flow to connect the user and obtain their access token through your backend.
2. Get a Web App Token
With the user's access token obtained from the previous step, request a limited one-hour web app token:
curl -X POST https://backend.earthmiles.app/api/oauth/webapp-token \
-H "Authorization: Bearer USER_ACCESS_TOKEN" \
-H "Content-Type: application/json"
This returns a temporary token valid for 1 hour, specifically for web app authentication. This request should be made from your backend server to keep the access token secure.
Keep Token Safe
The web app token is exclusively for the web app. Do not use it for anything else and ensure it is kept secure. Only pass it to the WebView and do not expose it elsewhere in your application.
3. Configure the WebView URL
Load the Earth Miles web app with your membership parameters:
| Parameter | Description |
|---|---|
country |
Two-letter country code (e.g., DK, NO) |
language |
Two-letter language code (e.g., da, en, no) |
membership |
Your unique membership ID (provided by Earth Miles) |
4. Inject the Authentication Token
Pass the web app token to the WebView by injecting it into the window object.
import android.webkit.WebView
import android.webkit.WebViewClient
import android.graphics.Bitmap
// Get the token from your backend
val token = "eyJhbGciOi..."
webView.settings.javaScriptEnabled = true
webView.webViewClient = object : WebViewClient() {
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
super.onPageStarted(view, url, favicon)
// Inject the auth token before the page loads
view?.evaluateJavascript(
"window.AUTH_TOKEN = '$token';",
null
)
}
}
// Load the Earth Miles web app
val webAppUrl = "https://webapp.earthmiles.app/?country=DK&language=da&membership=YOUR_MEMBERSHIP_ID"
webView.loadUrl(webAppUrl)
import WebKit
// Get the token from your backend
let token = "eyJhbGciOi..."
// Create a script to inject the auth token
let script = WKUserScript(
source: "window.AUTH_TOKEN = '\(token)';",
injectionTime: .atDocumentStart,
forMainFrameOnly: true
)
let controller = WKUserContentController()
controller.addUserScript(script)
let config = WKWebViewConfiguration()
config.userContentController = controller
let webView = WKWebView(frame: .zero, configuration: config)
// Load the Earth Miles web app
let urlString = "https://webapp.earthmiles.app/?country=DK&language=da&membership=YOUR_MEMBERSHIP_ID"
if let url = URL(string: urlString) {
webView.load(URLRequest(url: url))
}
Token Expiration
The web app token expires after 1 hour. There are no refresh tokens for web app tokens, so you must request a new token from your backend when it's near expiration. You can request a new token at any time using the user's access token.
5. Enable Geolocation Access
QRCode rewards in the Earth Miles system require location verification to confirm that users are near the physical location before they can redeem rewards. You must configure your WebView to allow geolocation access.
import android.webkit.GeolocationPermissions
import android.webkit.WebChromeClient
webView.settings.javaScriptEnabled = true
webView.settings.setGeolocationEnabled(true)
webView.webChromeClient = object : WebChromeClient() {
override fun onGeolocationPermissionsShowPrompt(
origin: String?,
callback: GeolocationPermissions.Callback?
) {
// Grant permission to the web app
callback?.invoke(origin, true, false)
}
}
You'll also need to request location permission from the user in your app's manifest:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
And request runtime permission:
import android.Manifest
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.content.ContextCompat
import android.content.pm.PackageManager
// Register the permission launcher
private val requestPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted: Boolean ->
if (isGranted) {
// Permission granted, WebView can now access location
} else {
// Permission denied, inform user that location features won't work
}
}
// Request permission
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
requestPermissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION)
}
import WebKit
import CoreLocation
class ViewController: UIViewController, WKUIDelegate, CLLocationManagerDelegate {
var webView: WKWebView!
var locationManager: CLLocationManager!
override func viewDidLoad() {
super.viewDidLoad()
// Set up location manager
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
// Configure WebView (+ token injection explained before)
let config = WKWebViewConfiguration()
webView = WKWebView(frame: .zero, configuration: config)
webView.uiDelegate = self
view = webView
// Load the URL
let urlString = "https://webapp.earthmiles.app/?country=DK&language=da&membership=YOUR_MEMBERSHIP_ID"
if let url = URL(string: urlString) {
webView.load(URLRequest(url: url))
}
}
// WKUIDelegate method - prompts are used by some web apps for geolocation
func webView(
_ webView: WKWebView,
runJavaScriptAlertPanelWithMessage message: String,
initiatedByFrame frame: WKFrameInfo,
completionHandler: @escaping () -> Void
) {
completionHandler()
}
}
Note: WKWebView handles geolocation through the JavaScript Geolocation API. When the web app requests location access, WKWebView will automatically use the iOS location permissions you've granted. Ensure your app has NSLocationWhenInUseUsageDescription in Info.plist and has requested location authorization as shown above.
Add the location usage description to your Info.plist:
Location Permission Required
Without geolocation access, users will not be able to redeem QRCode rewards. Make sure to request and handle location permissions properly in your app.