Search code examples
androidflutterdarthttpweb

Flutter HTTP server - serve flutter web in another app


I have created two Flutter applications. The first is Android app and contains an HTTP server that I want to use to serve this application via a web page. The second is Flutter web application. I built the second application and thanks to that I got files like index.html, main.dart.js and others. I would like to add these files to the first application so that when the HTTP server is turned on and the correct web page is loaded with the appropriate IP and port, this second application will be displayed. Is this possible? I have added these files to the assets folder, I have also added them to pubspec.yaml. I created a function that reads the index.html and sends it to the client using request.response.write.

assets folder

Future<void> showWeb(HttpRequest request) async {
  String _content = await rootBundle.loadString('assets/files/web/index.html');
  request.response
    ..statusCode = HttpStatus.ok
    ..headers.set("Content-Type", "application/javascript; charset=utf-8")
    ..write(_content)
    ..close();
}

I put "text/html" as the header, which throws me an error "content type mismatch". When I add "application/javascript" as a header, I get the source code of the html file.

Is it possible to view the Flutter web app using an HTTP server?


Solution

  • After some time I came back to this project and came up with a solution to my problem. Maybe it will help someone.

    1. Build the Flutter web application and copy the /build/web folder.
    2. In the second application, create an "assets" folder and paste the following folder into it
    3. Put the following paths into pubspec.yaml (you may have more, it's up to your check, but this is the default):
        - assets/web/
        - assets/web/assets/
        - assets/web/assets/fonts/
        - assets/web/assets/packages/cupertino_icons/assets/
        - assets/web/assets/shaders/
        - assets/web/canvaskit/
        - assets/web/canvaskit/profiling/
        - assets/web/icons/
    
    1. Create a function to handle a get request
    void handleGet(HttpRequest request) async {
      final path = request.uri.path;
      String _content;
      Uint8List _contentByte;
      String _mimeType;
      bool isItByte;
      try {
        isItByte = false;
        if (path == '/') {
          _content = await rootBundle.loadString('assets/web/index.html');
          _mimeType = 'text/html; charset=utf-8';
        } else {
          var dotoffset = path.lastIndexOf('.');
          if (path.substring(dotoffset) == '.png' ||
              path.substring(dotoffset) == '.ttf' ||
              path.substring(dotoffset) == '.otf') {
            _contentByte = await File('assets/web' + path.toString()).readAsBytes();
            isItByte = true;
          } else {
            _content = await rootBundle.loadString('assets/web' + path.toString());
          }
    
          _mimeType = dotoffset == -1
              ? 'text/plain; charset=utf-8'
              : {
                  '.html': 'text/html; charset=utf-8',
                  '.css': 'text/css; charset=utf-8',
                  '.js': 'text/javascript; charset=utf-8',
                  '.csv': 'text/csv; charset=utf-8',
                  '.txt': 'text/plain; charset=utf-8',
                  '.ico': 'image/x-icon',
                  '.jpg': 'image/jpg',
                  '.jpeg': 'image/jpeg',
                  '.png': 'image/png',
                  '.gif': 'image/gif',
                  '.svg': 'image/svg+xml',
                  '.json': 'application/json',
                  '.xml': 'application/xml',
                  '.ttf': 'font/ttf',
                  '.otf': 'font/otf'
                }[path.substring(dotoffset)];
        }
        if (isItByte) {
          request.response
            ..statusCode = HttpStatus.ok
            ..headers.set("Content-Type", _mimeType)
            ..write(_contentByte)
            ..close();
        } else {
          request.response
            ..statusCode = HttpStatus.ok
            ..headers.set("Content-Type", _mimeType)
            ..write(_content)
            ..close();
        }
      } catch (e) {
        print(e.toString());
      }
    }
    

    It is necessary that both applications have the same font and then everything works.

    The code is not optimized, I'm still working on it, but it's enough for an illustration.