Skip to main content

Command Palette

Search for a command to run...

Flutter Promised “Write Once, Run Anywhere.” My Plugin Didn’t, Until Now.

Updated
6 min read
Flutter Promised “Write Once, Run Anywhere.” My Plugin Didn’t, Until Now.
M

Experienced Android Developer with a demonstrated history of working for the IT industry. Skilled in JAVA, Dart, Flutter, and Teamwork. Strong Application Development professional with a Bachelor's degree focused in Computer Science & Engineering from Daffodil International University-DIU.

When I started building flutter-crisp-chat, I had one clear goal.

Bring Crisp live chat into Flutter apps the way mobile developers expect it native UI on Android and iOS, one package, one API, no painful platform channels for every small thing.

And for a long time, that worked.

Apps shipped. Issues came in. PRs got merged. Releases went to pub.dev.

But every time someone ran:

flutter devices

and saw more than just iPhone and Android, a quiet question followed:

“Does this work on Web?”

“What about macOS?”

“We’re Flutter everywhere — except support chat.”

That question sat in the back of my mind longer than I want to admit.

Because Flutter’s whole pitch is not “write twice, hope for the best.”

It is write once, run anywhere.

My plugin was honest on two platforms.

Not on six.

Until crisp_chat 2.5.0

The Moment I Couldn’t Hand-Wave Anymore

It started like most real open-source work.

Not with a roadmap.

With an issue.

Someone opened #81 and asked something simple:

Can we support Mac, Windows, and Linux?

On the surface, it sounds like a feature request.

Underneath, it was bigger.

They were not asking for a experiment branch.

They were saying:

“We already chose Flutter so we do not maintain separate apps. Why is chat the one feature that breaks that rule?”

And they were right.

If your product is a Flutter app on phone and a Flutter app on desktop and maybe a Flutter web dashboard, you do not want three different Crisp integrations in your head.

You want one.

That issue was the line in the sand for me.

Either crisp_chat grows up with Flutter, or it stays a mobile plugin forever.

I chose the first.

What “All Platforms” Actually Meant

Before writing code, I had to be honest about what Crisp offers.

On Android and iOS, Crisp ships native SDKs — real chat UI, the mobile experience people know.

On Web and desktop, there is no parallel “Crisp desktop SDK” in the same shape.

Crisp’s answer there is the Web Chat SDK — load client.crisp.chat, configure the widget, open the chatbox.

So “all platforms” did not mean “copy-paste the Android folder six times.”

It meant:

  • Mobile → native SDKs (unchanged strength)

  • Web + desktop → same web client, hosted the Flutter way

One Dart API on top.

FlutterCrispChat.openCrispChat(config: …) should mean something on every target.

That was the bar.

Web — The First Time the Plugin Felt “Flutter”

Web was the unlock.

Flutter already has a path for federated plugins.

No giant method channel on Chrome.

Instead: Dart talks to JavaScript, JavaScript talks to Crisp.

The Crisp script loads from https://client.crisp.chat/l.js.

Your CrispConfig — website ID, user email, segments — still maps to the same ideas you use on mobile.

From the app’s point of view, it still feels like:

await FlutterCrispChat.openCrispChat(config: config);

That mattered more than any internal file name.

Because the worst multi-platform story is not “hard to implement.”

It is “hard to explain.”

If Web needs a completely different package, Flutter’s promise is already broken before you ship.

Desktop — Where “Run Anywhere” Meets Real Machines

Desktop was the part that made 2.5.0 feel real.

macOS. Windows. Linux.

For each, the plugin opens a window with the same Crisp web experience inside — using desktop_webview_window.

If the system WebView is missing or broken, it falls back to the browser.

Not the prettiest path.

But a honest one.

Desktop taught me things mobile never did:

  • macOS sandbox without network entitlement → blank WebView, no error drama, just white screen

  • WKWebView refusing external scripts on data: URLs → embed HTML from file:// instead

  • “Works on my Mac” is not a release strategy → the example app got linux, macos, and windows runners so I could actually run what I ship

None of that is in the tagline “write once, run anywhere.”

But it is in the work of making it true.

One API, Six Targets

This is what 2.5.0 means in practice:

Android — Native Crisp Android SDK

iOS — Native Crisp iOS SDK

Web — Crisp Web Chat SDK

macOS — Web SDK in a desktop WebView

Windows — Web SDK in a desktop WebView

Linux — Web SDK in a desktop WebView

Six targets.

One package:

dependencies:
  crisp_chat: ^2.5.0

Same import.

Same CrispConfig.

Same “open chat” moment in your app — whether your user is on a phone, a browser tab, or a desktop window.

That is what I wanted when I said yes to issue #81.

Not a checkbox.

A Flutter-shaped integration.

The Trade-Off I Won’t Hide

Going everywhere has a cost.

Flutter 3.24+ and Dart 3.5+ for Web and desktop (desktop WebView dependency).

New packages: desktop_webview_window, http, url_launcher, web.

Push notification helpers are mobile — on Web and desktop they are no-ops, because that is the truth, not a missing TODO.

If you are mobile-only on an older SDK, 2.4.8 is still there.

I would rather say that in a blog post than in a GitHub issue six months later.

What Changed for Me as a Maintainer

Before 2.5.0, I described crisp_chat as a mobile Crisp plugin.

After 2.5.0, I describe it as a Flutter Crisp plugin.

Small words.

Big shift.

The example app is not just “the Android demo” anymore.

You can run:

flutter run -d chrome - dart-define=websiteId=YOUR_WEBSITE_ID
flutter run -d macos - dart-define=websiteId=YOUR_WEBSITE_ID

CI runs analyze and tests on every push.

The docs have a supported platforms page that reads like a contract, not a wish list.

That is what “until now” means in the title.

Not perfection on day one.

Parity with Flutter’s platform list — finally.

What I’d Tell Past Me

If you maintain a Flutter plugin today:

  1. Listen for “what about X?” — that is often your real roadmap.

  2. Do not fake native on Web — use the platform’s real client (for Crisp, that is the web SDK).

  3. Ship an example that runs where you claim support — folders are documentation.

  4. Keep one Dart surface — multi-platform dies the moment you need if (kIsWeb) use_other_package.

Flutter promised write once, run anywhere.

Plugins either help that promise, or quietly break it.

For a long time, mine broke it.

2.5.0 is my attempt to keep the promise.

Try It

pub.dev: https://pub.dev/packages/crisp_chat

Platform guide: https://alamin-karno.github.io/flutter-crisp-chat/getting_started/supported_platforms.html

dependencies:
  crisp_chat: ^2.5.0

Open an issue if a platform still feels left out.

The best plugins are not finished.

They just stop pretending the world is only two app stores.

More from this blog

Learn with Alamin Karno

44 posts

Welcome to Learn with Alamin Karno, a place to explore technology, programming, AI, freelancing, productivity, and personal growth. Discover practical tutorials, insights, and tips designed to help students, developers, and lifelong learners build skills and achieve their goals.