2

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?

10
  • Is it possible to view the Flutter web app using an HTTP server? I do not understand that question. Your http server serves a html file from assets. You can check if your server does its job from any browser on that device or any browser on devices in the same network. Commented Mar 24, 2022 at 9:21
  • @blackapps I tried to upload the web application to Firebase, where it loads normally. But I would like the user of the application to just tap the http server in the application and the web browser on the localhost with the given port will display the web application. I don't want to write html and css, I want to create a Flutter web application and put the generated files (html, etc) into the first application that displays them on the given port. Commented Mar 24, 2022 at 9:50
  • That can all be. But is it relevant for the problem you encountered? It seems that serving a html page goes wrong. To test if your server works you can start with a simple html page. Commented Mar 24, 2022 at 9:55
  • put the generated files (html, etc) into the first application that displays them on the given port. I cannot follow you. The first application serves those files. It will display nothing. The browser displays. Commented Mar 24, 2022 at 9:57
  • @blackapps That worked too. I added an html file where I only added the title and text to the body to test that it worked. Then I tried adding the generated html file. It reported to me that I was missing main.dart.js. So I added it to the folder as well. It didn't work. So I added the whole generated folder, but that didn't work either. And as I wrote, when I put text/html as header, it says content type mismatch and when application/javascript, it only shows the source code. I'm doing something wrong Commented Mar 24, 2022 at 9:59

1 Answer 1

2

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.

Sign up to request clarification or add additional context in comments.

3 Comments

The png/ttf/otf branch of this does not work - in two ways. First, File(....) doesn't read relative to assets/ so it can't find the path Second, the bytes served in that case are not handled correctly by the web viewer.
Okay, so I have to use function rootBundle.load(<pathToAssets>).asStream()?
Yeah, I believe that's the correct approach, but I had issues getting it to work - even when it read the correct bytes it appeared to serve them improperly, but I didn't spend a lot of time on it.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.