Flutter has supported stable desktop device development for some time now, and I have to say that Flutter’s multi-platform support features really smell good. I have no experience in desktop development myself, but I did develop a desktop application using Flutter. The purpose of Flutter is simply to format and model the input JSON.

Without further ado, let’s look at the actual results. Project source code address

The development environment is as follows:

Flutter: 2.8.1

The Dart: 2.15.1

IDE: VSCode

JSON is a data format that we often deal with in our daily development work. It has six data types: NULL, NUM, String, Object, array and bool. We have to love it and hate it. I love it because it’s really convenient and concise as a format for data processing. However, when we do Flutter development and need to deal with JSON parsing, it can be very tricky, because the Flutter does not reflect, resulting in a complex mapping of json to model by hand. It looks something like this.

void fromJson(Map<String.dynamic>? json) {
	if (json == null) return;
	age = json['age'];
	name = json['name']????' ';
}
Copy the code

A small amount of data is acceptable, but when it is large, even handwriting can make you doubt your life. Not to mention the possibility of error with handwriting. Fortunately, there is an official tool ** jSON_serializable ** that can automatically generate this conversion code, and also solve the hole of the FLUTTER bound json to model. Of course, there are also web sites dedicated to parsing JSON that automatically generate dart code, which users can easily copy into their projects.

This project takes JSON parsing as a starting point to take a look at how Flutter is developed for desktop applications.

1. Create a project

Our Flutter project needs to support desktop devices. We first need to modify the Settings of the Flutter. Below, let our project support Windows and MacOS.

flutter config --enable-windows-desktop
flutter config --enable-macos-desktop
Copy the code

Next create our template project using the flutter create command.

flutter create -t app --platforms macos,windows  hello_desktop
Copy the code

With the project created, we are ready to run.

2. Function introduction

First, take a look at the overall interface. The interface consists of four parts: function module, file selection module, input module and output module.

The auto-correction feature here helps us to convert abnormal json into the correct format, but it is in the development stage and can be ignored.

3. Record key technical points & difficulties:

1, Control Window Window

When we create a new desktop application, the default template has an Appbar, and the application can be dragged around, zoomed in and out, or shrunk to a very small size. However, once we remove the navigation bar, the window cannot be dragged with the mouse, and we often do not want users to zoom our window too small, which will lead to page abnormalities and some important information is not displayed fully. Therefore, the third-party component Bitsdojo_window is required. Through bitsdojo_window, we can achieve window customization, drag, minimum size, maximum size, window border, window top zoom, zoom, close button and so on.

2, mouse movement capture

The InkWell component captures gestures, mouse, and stylus movements and stays

tip = InkWell(
    child: tip,
    hoverColor: Colors.white,
    highlightColor: Colors.white,
    splashColor: Colors.white,
    onHover: (value) {
      bool needChangeState = widget.showTip ! = value;
      if (needChangeState) {
        if (value) {
          // Hover the mouse over the tip
          showTip(context, PointerHoverEvent());
        } else {
          overlay?.remove();
        }
      } 
      widget.showTip = value;
    },
    onTap: () {},
  );
Copy the code

3. The prompt box is displayed when the mouse stops over the specified text, and the prompt box is hidden when the mouse is removed

This function is the UI interaction interface after mouse movement. To display a prompt box on a window, use an Overlay. Note that since the root of the text on the Overlay is not a Material style component, it will be underlined in yellow. So make sure you wrap text with Material. And you must give the created OverlayEntry a location, otherwise it will display in full screen.


Widget entry = const Text(' Auto repair refers to the inputIf the JSON format is incorrect, the tool will automatically fill in the correct JSON format.Such as "",{},Such as: ', style:TextStyle(
        fontSize: 14,
        color: Colors.black
      ),
      );

entry = Material(
      child: entry,
    );

/ /... Other code
OverlayEntry overlay = OverlayEntry(
          builder: (_) {
            returnentry; });Overlay.of(context)?.insert(overlay);

       this.overlay = overlay;
  }
Copy the code

4, read the mouse drag file

Reading a file that says a table is being dragged initially tried using the InkWell component, but the component couldn’t recognize the mouse in the drag and couldn’t get the file information from it. So give up. Later, according to the article “Flutter-2 Days write a desktop APP”, a component called Desktop_drop that can read and drag files can meet the requirements.

5. Local file selection

Using the open source component File_picker, the action after selecting an image is the same as the action after dragging and dropping an image.

TextField displays rich text

Textfield To display rich text, you need to customize the TextEditingController. Rewrite the buildTextSpan method.

class RichTextEditingController extends TextEditingController {

// ...

@override
  TextSpan buildTextSpan(
      {required BuildContext context,
      TextStyle? style,
      required bool withComposing}) {
    if (highlight) {
      TextSpan text;
      String? input = OutputManager().inputJSON;
      text = _serializer.formatRich(input) ?? const TextSpan();
      return text;
    }
    String json = value.text;
    returnTextSpan(text: json, style: style); }}Copy the code

7. An error occurs when exporting the file

The following error occurs when you export files, indicating that you do not have permission to access files in the corresponding directory.

flutter: path= /Users/zl/Library/Containers/com.example.jsonFormat/Data/Downloads
[ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: FileSystemException: Cannot open file, path = '/Users/zl/Library/Containers/com.example.jsonFormat/Data/Downloads/my_format_json.json' (OS Error: Operation not permitted, errno = 1)
Copy the code

Find instructions about permissions in Apple’s development documentation. Authorized one of the private key of the key for the com. Apple. Security. The files. Downloads. The read – write, for users to download folder to read/write access. Then, using the Xcode open Flutter MAC application project, modify the project directory DebugProfile. Entitlements file, Com is added to the entitlements file. Apple. Security. Files. Downloads. The read – write, and set the value to YES, save and restart Flutter project. Found that you can read and write files to the download directory.

Of course, this is normal operation. Another trick is to turn off the sandbox mechanism. Set the App Sandbox for Entitlements file to NO. So we can access any path. Of course, turning off your app’s sandbox also turns off your app’s protection mechanism, so use this option with caution.


TODO List:

  • Json auto-correction
  • Model code highlights
  • Custom export path

Reference Documents:

Flutter desktop Support

Flutter desktop support

Flutter-2 days write a desktop APP

pub.dev-window

Flutter Desktop – bitsdojo-window – bilibili

Apple development permission document