To use our SDK with Flutter, you only need to add a JavaScriptChannel named FlutterWebView
when using the webview_flutter package. This channel allows our server to communicate with WebViews in Flutter. See the example below:
// ignore_for_file: avoid_print
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
// https://pub.dev/packages/webview_flutter
import 'package:webview_flutter/webview_flutter.dart';
// https://pub.dev/packages/webview_flutter_android
import 'package:webview_flutter_android/webview_flutter_android.dart';
// https://pub.dev/packages/webview_flutter_wkwebview
import 'package:webview_flutter_wkwebview/webview_flutter_wkwebview.dart';
const String sdkMobileServer = 'https://sdk-mobile.cert.zerohash.com/v1';
const String zeroHashAppsURL = 'https://web-sdk.cert.zerohash.com';
class WebViewScreen extends StatefulWidget {
const WebViewScreen({super.key});
@override
WebViewScreenState createState() => WebViewScreenState();
}
class WebViewScreenState extends State<WebViewScreen> {
String token = "";
late WebViewController controller;
@override
void initState() {
super.initState();
fetchData();
}
// Setup webview controller with the token in the URL
// Do not remove FlutterWebView channel, it is required for communication between webview and webpage
void setupController() {
late final PlatformWebViewControllerCreationParams params;
if (WebViewPlatform.instance is WebKitWebViewPlatform) {
params = WebKitWebViewControllerCreationParams(
allowsInlineMediaPlayback: true,
mediaTypesRequiringUserAction: const <PlaybackMediaTypes>{},
);
} else {
params = const PlatformWebViewControllerCreationParams();
}
controller = WebViewController.fromPlatformCreationParams(params);
if (controller.platform is AndroidWebViewController) {
AndroidWebViewController.enableDebugging(true);
(controller.platform as AndroidWebViewController).setMediaPlaybackRequiresUserGesture(false);
}
controller
..setJavaScriptMode(JavaScriptMode.unrestricted)
..addJavaScriptChannel('FlutterWebView', onMessageReceived: onMessageReceived)
..loadRequest(
Uri.parse('$sdkMobileServer?achDepositsJWT=$token&cryptoBuyJWT=$token&cryptoSellJWT=$token&cryptoWithdrawalsJWT=$token&fiatWithdrawalsJWT=$token&userOnboardingJWT=$token&zeroHashAppsURL=$zeroHashAppsURL')
);
}
// Fetch token from the server and setup webview controller with the token
Future<void> fetchData() async {
try {
final url = Uri.parse('<API_URL_TO_FETCH_TOKEN>');
final response = await http.post(url,
body: json.encode(
{
'participant_code': '<PARTICIPANT_CODE>',
'permissions': [
'crypto-buy',
'crypto-sell',
'crypto-withdrawals',
'fiat-deposits',
'fiat-withdrawals',
]
}
)
);
if (response.statusCode >= 200 && response.statusCode < 300) {
// Store the data in the 'token' and setup webview controller
var body = json.decode(response.body);
setState(() {
token = body['message']['token'];
});
setupController();
} else {
print('Failed to fetch data: $response');
}
} catch (e) {
// Handle network or API call errors
print('Failed to fetch data: $e');
}
}
// Handle messages received from the webview
void onMessageReceived(JavaScriptMessage message) {
try {
print('Receving message: ${message.message}');
// Parse the message JSON
Map<String, dynamic> messageJson = jsonDecode(message.message);
if (messageJson.containsKey('type')) {
// Indicates that the SDK mobile is ready to receive postMessage
if (messageJson['type'] == 'SDK_MOBILE_READY') {
print('SDK mobile ready, opening modal');
// Open the modal for the app with the identifier 'crypto-sell'
controller.runJavaScript('window.postMessage({ "type": "OPEN_MODAL", "payload": { "appIdentifier": "crypto-buy"}})');
}
}
} catch (e) {
print('Error parsing JSON: $e');
}
}
Widget _buildChild() {
// If the token is empty, show a loading message
if (token.isEmpty) {
return const Center(
child: Text('Fetching token...'),
);
}
// Return the WebViewWidget with the controller
return WebViewWidget(controller: controller);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: SafeArea(
child: Column(
children: [
Expanded(
child: _buildChild(),
),
],
),
),
),
);
}
}