start method

  1. @override
Future<void> start()
override

Starts the server on http://localhost:[port]/.

NOTE for iOS: For the iOS Platform, you need to add the NSAllowsLocalNetworking key with true in the Info.plist file (See ATS Configuration Basics):

<key>NSAppTransportSecurity</key>
<dict>
   <key>NSAllowsLocalNetworking</key>
   <true/>
</dict>

The NSAllowsLocalNetworking key is available since iOS 10.

Officially Supported Platforms/Implementations:

  • Android WebView
  • iOS WKWebView
  • macOS WKWebView
  • Windows WebView2
  • Linux WPE WebKit

Use the PlatformInAppLocalhostServer.isMethodSupported method to check if this method is supported at runtime.

Implementation

@override
Future<void> start() async {
  if (this._started) {
    throw Exception('Server already started on http://localhost:$_port');
  }
  this._started = true;

  final completer = Completer();

  runZonedGuarded(
    () {
      HttpServer.bind('127.0.0.1', _port, shared: _shared).then((server) {
        if (kDebugMode) {
          print('Server running on http://localhost:' + _port.toString());
        }

        this._server = server;

        final subscription = server.listen((HttpRequest request) async {
          if (await _customOnData?.call(request) ?? false) {
            // if _customOnData returns true,
            // it means that the request has been handled
            return;
          }

          Uint8List body = Uint8List(0);

          var path = request.requestedUri.path;
          path = (path.startsWith('/')) ? path.substring(1) : path;
          path += (path.endsWith('/')) ? _directoryIndex : '';
          if (path == '') {
            // if the path still empty, try to load the index file
            path = _directoryIndex;
          }
          path = _documentRoot + path;

          try {
            body = (await rootBundle.load(
              Uri.decodeFull(path),
            )).buffer.asUint8List();
          } catch (e) {
            if (kDebugMode) {
              print(Uri.decodeFull(path));
              print(e.toString());
            }
            request.response.close();
            return;
          }

          var contentType = ContentType('text', 'html', charset: 'utf-8');
          if (!request.requestedUri.path.endsWith('/') &&
              request.requestedUri.pathSegments.isNotEmpty) {
            final mimeType = MimeTypeResolver.lookup(
              request.requestedUri.path,
            );
            if (mimeType != null) {
              contentType = _getContentTypeFromMimeType(mimeType);
            }
          }

          request.response.headers.contentType = contentType;
          print(request.response.headers);
          request.response.add(body);
          request.response.close();
        });
        subscription.onDone(() => _clearServerReference(server));
        subscription.onError((Object error, StackTrace stackTrace) {
          _clearServerReference(server);
        });

        completer.complete();
      });
    },
    (e, stackTrace) {
      if (kDebugMode) {
        print('Error: $e $stackTrace');
      }
    },
  );

  return completer.future;
}