This document describes how to implement a custom login/sign-up page using a WebView.
Communication between the custom
web page and the Flutter application is handled via the WebtritLoginChannel JavaScript channel,
allowing the web UI to
securely transmit user data to the app for authentication.
An example HTML file is available here: custom_signup.html
The interaction between the web page and the Flutter app follows a clear protocol built around a JavaScript channel.
All communication is facilitated through the WebtritLoginChannel object, which is injected into
the WebView's
JavaScript context by the Flutter app. This channel exposes a postMessage() method for sending
data from the web page
to the app.
After the web page is loaded, the Flutter app can call the global JavaScript function
initializePage(initData) to pass
initial data, such as localization settings or pre-filled form values.
Function Signature: initializePage(initData)
initData: An object containing initialization data. Common keys include:locale: The current language setting of the app (e.g.,"en").prefillEmail: An email address to pre-populate in an input field.
It is the responsibility of the web page to implement this function to handle the incoming data.
Example Implementation:
function initializePage(initData) {
const { locale, prefillEmail } = initData || {};
if (locale) {
// Apply translations based on the locale
}
if (prefillEmail) {
document.getElementById("email").value = prefillEmail;
}
}Example Call from Flutter:
final script = '''
if (typeof window.initializePage === 'function') {
window.initializePage({ "locale": "$locale" });
}
''';When the user completes an action (e.g., submitting a form), the web page must gather the data and
send it to the
Flutter app by calling WebtritLoginChannel.postMessage(). The message must be a stringified JSON
object with a
specific structure.
JSON Payload Structure:
event: A string identifying the action. Currently, this must always be"signup".data: An object containing the key-value pairs of user-submitted data.
A special key, tenant_id, can be included in the data object. If present, the app will modify
the API request URL
to core-url/tenant/{tenant_id}/api/v1/user.
Example JSON Payload:
{
"event": "signup",
"data": {
"email": "user@example.com",
"key1": "value1",
"tenant_id": "d1bbfa00-0298-4667-ba81-9c432a416a10"
}
}Below is a minimal HTML structure demonstrating how to collect an email and send it to the Flutter
app. This example
also includes the initializePage function for handling data from Flutter.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>OTP Login</title>
</head>
<body>
<div class="form-container">
<p class="description" id="descriptionText">
Enter your email to receive a one-time password (OTP) for login.
</p>
<div class="form-group">
<label for="email" id="emailLabel">Email</label>
<input id="email" name="email" required>
</div>
</div>
<button class="fixed-button" id="submitButton" onclick="handleLogin()">
<span class="button-text" id="submitButtonText">Submit</span>
<div class="spinner"></div>
</button>
<script>
function handleLogin() {
const email = document.getElementById("email").value;
if (!email) {
alert("Please enter your email.");
return;
}
const payload = {
event: "signup", // For now, this should always be 'signup'
data: {
email: email, // Here can be any key-value pairs
key1: "value1",
key2: "value2"
}
};
if (window.WebtritLoginChannel) {
WebtritLoginChannel.postMessage(JSON.stringify(payload));
} else {
console.error("WebtritLoginChannel not found.");
}
}
function initializePage(initData) {
const { locale, prefillEmail } = initData || {};
if (locale) {
// apply translations based on locale
}
if (prefillEmail) {
document.getElementById("email").value = prefillEmail;
}
}
</script>
</body>
</html>When the Flutter app receives a message from the web page via postMessage(), it performs the
following steps:
-
Receiving the Message The Flutter
WebViewhas a registered JavaScript channel namedWebtritLoginChannel. Its message handler is triggered whenpostMessage()is called from JavaScript. -
Parsing the Data The incoming message (a JSON string) is parsed into a Dart
Map. The app verifies theeventkey (expectingsignup) and extracts thedataobject. -
Handling the API Request The key-value pairs from the
dataobject are sent as the body of aPOSTrequest to theapi/v1/userendpoint. If atenant_idkey is present in thedataobject, the request URL is modified to:core-url/tenant/{tenant_id}/api/v1/user -
Result Handling & Navigation After processing the API response, the app navigates the user from the custom login
WebViewto the appropriate native screen, such as an OTP verification page or a success screen.
For detailed instructions on configuring the WebView component and integrating custom HTML files
into your project,
please refer to the Features documentation.