4

I'm using Flutter 2.5.2. I have a project which is to be used for both web and mobile (Android / iOS).

There is one particular widget where I need to use one version of the widget when deploying for web, which uses the JS and HTML packages. When deploying for mobile, I need to use a different version which just uses standard Flutter widgets. (The reasons for this are complex - I'm embedding Unity inside flutter).

So for example, I have this web_player.dart version for web:

import 'dart:html' as html;
import 'package:js/js.dart';
import 'package:flutter/material.dart';

@JS('loadPlayer')
external String loadPlayer();

class WebVersion extends StatelessWidget {
  const WebVersion({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // Use the HTML package and return an HtmlElementView
  }
}

And this mobile_player.dart version for mobile:

class MobileVersion extends StatelessWidget {
  const MobileVersion({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Text("Mobile version")
  }
}

Building for web is fine. The problem is that when I build for mobile, the build breaks with:

Error: Not found: 'dart:js'

and

Error: Not found: 'dart:html'

I'm aware that these packages do not exist in the mobile platform, and I'm trying to find a workaround. I initially tried to conditionally use the WebPlayer or MobilePlayer widgets depending on the kIsWeb flag, but this didn't make any difference (I guess because kIsWeb is not a complile-time constant?)

So then I attempted to work around this using conditional imports. So, I created a stub player_stub.dart:


import 'package:flutter/material.dart';


Widget getPlayer() => throw UnsupportedError("This is a stub");

I import this stub in a wrapper Player widget:

import 'package:mypackage/player_stub.dart'
  if (dart.library.io) 'package:mypackage/mobile_player.dart'
  if (dart.library.js) 'package:mypackage/web_player.dart';

class Player extends StatelessWidget {

  const Player ();

  @override
  Widget build(BuildContext context) {
    return getPlayer();
  }
}

And then added stub implementations in my mobile_player.dart:

Widget getPlayer() => MobilePlayer();

and in my web_player.dart:

Widget getPlayer() => WebPlayer();

I was hoping this would resolve the build error by compile time tree shaking or something, but it doesn't.

How do I solve this? I'm totally stumped.

2 Answers 2

7

Just to answer my own question for others looking for an answer: the solution was moving the stub, the mobile widget and the web widget to a separate dart library.

The library uses conditional exports like this in it's root my_player_package.dart file:

export 'src/player_stub.dart'
  if (dart.library.js) 'src/web_player.dart'
  if (dart.library.io) 'src/mobile_player.dart';

So now I reference my separate library in my pubspec.yaml:

dependencies:

  ...

  my_player_package:
    path: ../my_player_package

And I can now import 'package:my_player_package/my_player_package.dart' and build for both web and mobile.

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

1 Comment

can u pls update the answer with full code(or link) like in question for better understanding.
2

I'm attempting to use the js package in a cross-platform app and this was my solution.

1. Create a js_stub.dart file

class JS {
  final String? name;
  const JS([this.name]);
}

allowInterop<F extends Function>(F f){
  throw UnimplementedError();
}

2. Use a conditional import statement

import 'package:pwa_install/js_stub.dart' if (dart.library.js) 'package:js/js.dart';

The rest of my code was left untouched and the app runs as expected on web and mobile.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.