Platform Examples
Complete store screens for Android (Kotlin & Java), iOS (Swift), React Native, and Flutter
Each example below is a complete store screen: it builds the store URL with credentials, enables JavaScript and DOM storage, locks to portrait, adds a native close button, and handles back navigation as described in WebView Setup.
Replace YOUR_API_KEY and ACCESS_TOKEN with your API key and the token from Authentication.
Android (Kotlin)
A dedicated Activity with a toolbar close button and hardware-back handling. Lock it to portrait in the manifest:
<activity
android:name=".StoreActivity"
android:screenOrientation="portrait" />import android.net.Uri
import android.os.Bundle
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.activity.OnBackPressedCallback
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
class StoreActivity : AppCompatActivity() {
private lateinit var webView: WebView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_store)
// Native close button — always available to the player
findViewById<Toolbar>(R.id.toolbar).setNavigationOnClickListener { finish() }
webView = findViewById(R.id.webView)
webView.settings.javaScriptEnabled = true
webView.settings.domStorageEnabled = true
webView.webViewClient = WebViewClient() // keep navigation inside the WebView
// Hardware back: WebView history first, then close the screen
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
if (webView.canGoBack()) webView.goBack() else finish()
}
})
val storeUrl = Uri.parse("https://store.playsuper.club/").buildUpon()
.appendQueryParameter("apiKey", "YOUR_API_KEY")
.appendQueryParameter("authToken", intent.getStringExtra("authToken"))
.appendQueryParameter("utm_content", "main_menu_button")
.build()
.toString()
webView.loadUrl(storeUrl)
}
}Android (Java)
import android.net.Uri;
import android.os.Bundle;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import androidx.activity.OnBackPressedCallback;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
public class StoreActivity extends AppCompatActivity {
private WebView webView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_store);
Toolbar toolbar = findViewById(R.id.toolbar);
toolbar.setNavigationOnClickListener(v -> finish());
webView = findViewById(R.id.webView);
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setDomStorageEnabled(true);
webView.setWebViewClient(new WebViewClient());
getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
@Override
public void handleOnBackPressed() {
if (webView.canGoBack()) {
webView.goBack();
} else {
finish();
}
}
});
String storeUrl = Uri.parse("https://store.playsuper.club/").buildUpon()
.appendQueryParameter("apiKey", "YOUR_API_KEY")
.appendQueryParameter("authToken", getIntent().getStringExtra("authToken"))
.appendQueryParameter("utm_content", "main_menu_button")
.build()
.toString();
webView.loadUrl(storeUrl);
}
}iOS (Swift)
A view controller with a navigation-bar close button, presented inside a UINavigationController. Portrait is enforced via supportedInterfaceOrientations:
import UIKit
import WebKit
class StoreViewController: UIViewController {
var webView: WKWebView!
let apiKey = "YOUR_API_KEY"
let authToken = "ACCESS_TOKEN"
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .portrait // the store is portrait-only
}
override func viewDidLoad() {
super.viewDidLoad()
title = "Rewards Store"
navigationItem.leftBarButtonItem = UIBarButtonItem(
barButtonSystemItem: .close,
target: self,
action: #selector(closeStore)
)
webView = WKWebView(frame: view.bounds)
webView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
// WKWebView has JavaScript and localStorage enabled by default
view.addSubview(webView)
var components = URLComponents(string: "https://store.playsuper.club/")!
components.queryItems = [
URLQueryItem(name: "apiKey", value: apiKey),
URLQueryItem(name: "authToken", value: authToken),
URLQueryItem(name: "utm_content", value: "main_menu_button"),
]
webView.load(URLRequest(url: components.url!))
}
@objc private func closeStore() {
dismiss(animated: true)
}
}
// Presenting the store from your game screen:
// let store = UINavigationController(rootViewController: StoreViewController())
// store.modalPresentationStyle = .fullScreen
// present(store, animated: true)React Native
A full-screen store using react-native-webview, with a close button and Android hardware-back handling:
import React, { useRef, useState, useEffect } from 'react';
import { BackHandler, Button, SafeAreaView, StyleSheet, View } from 'react-native';
import { WebView } from 'react-native-webview';
export function StoreScreen({ authToken, onClose }) {
const webViewRef = useRef(null);
const [canGoBack, setCanGoBack] = useState(false);
const params = new URLSearchParams({
apiKey: 'YOUR_API_KEY',
authToken,
utm_content: 'main_menu_button',
});
// Android hardware back: WebView history first, then close the screen
useEffect(() => {
const sub = BackHandler.addEventListener('hardwareBackPress', () => {
if (canGoBack) {
webViewRef.current?.goBack();
return true;
}
onClose();
return true;
});
return () => sub.remove();
}, [canGoBack, onClose]);
return (
<SafeAreaView style={styles.container}>
<View style={styles.toolbar}>
<Button title="Close" onPress={onClose} />
</View>
<WebView
ref={webViewRef}
source={{ uri: `https://store.playsuper.club/?${params.toString()}` }}
javaScriptEnabled={true}
domStorageEnabled={true}
onNavigationStateChange={(navState) => setCanGoBack(navState.canGoBack)}
/>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: { flex: 1 },
toolbar: { flexDirection: 'row', justifyContent: 'flex-end', padding: 8 },
});Lock the screen to portrait with your navigation library (e.g. orientation: 'portrait' in React Navigation screen options) or a package like react-native-orientation-locker.
Flutter
A full store page using webview_flutter, with an AppBar close button and back handling:
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
class StorePage extends StatefulWidget {
final String authToken;
const StorePage({super.key, required this.authToken});
@override
State<StorePage> createState() => _StorePageState();
}
class _StorePageState extends State<StorePage> {
late final WebViewController _controller;
@override
void initState() {
super.initState();
final storeUri = Uri.https('store.playsuper.club', '/', {
'apiKey': 'YOUR_API_KEY',
'authToken': widget.authToken,
'utm_content': 'main_menu_button',
});
_controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..loadRequest(storeUri);
}
// Back: WebView history first, then close the page
Future<void> _handleBack() async {
if (await _controller.canGoBack()) {
await _controller.goBack();
} else if (mounted) {
Navigator.of(context).pop();
}
}
@override
Widget build(BuildContext context) {
return PopScope(
canPop: false,
onPopInvokedWithResult: (didPop, _) {
if (!didPop) _handleBack();
},
child: Scaffold(
appBar: AppBar(
title: const Text('Rewards Store'),
leading: IconButton(
icon: const Icon(Icons.close),
onPressed: () => Navigator.of(context).pop(),
),
),
body: WebViewWidget(controller: _controller),
),
);
}
}DOM storage is enabled by default in webview_flutter on Android. If you use a different WebView package, make sure localStorage is enabled.
Next, handle token expiry, logout, and account switching in Session Management.