Go-flutter: Examples of passing data from Go to the flutter front end

Created on 15 Jul 2019  路  13Comments  路  Source: go-flutter-desktop/go-flutter

Hey there,
Big fan of the work you guys are doing here. I had been learning Go the last few months and kept trying out different UI packages and so far this one definitely seems to be the way to go. I was working on building my application which runs as a taskbar background application and then uses flutter as a config window. I got to the point where I was ready to connect up some of my backend logic with the front end when I realized that I have yet to find an example of how to actually do that? I assume that data binding is probably needed or similar, but how do I go about doing that?

Specifically what I was trying to do at the moment was, my background Go code, upon opening the app reads data from a config file and stores it in a struct and then I was going to use list view to display data within the various sections of the config on the main page of my flutter app. All I have seen so far in the way of actual Go code being involved was simply starting the application and setting a few options. Does anyone have any links to any similar examples or info?

Thanks!
-MH

example plugin question

Most helpful comment

I appreciate the thorough reply. I do confess since Dart/Flutter in general is new to me, I suppose it was a bit difficult for me to differentiate what would be a go-flutter question and what would be a plain dart/flutter question. That is probably my biggest issue to overcome. Once I figure that out, it will probably help me to better locate more repos with code samples which are closer to what I am hoping to achieve. I tried to just use keywords from the tutorial to see if anything came up, but I suppose they were not related in the way I was expecting them to be.

Such as, I tried to look up "go-flutter" and "MethodChannel" since those were both things I used from the tutorial, hoping to see other people who have implemented it and what they were doing and how, but unfortunately that only yielded 7 results, and they were all from this repo, lol. Now I see that MethodChannel isn't / wasn't used along with anything go-flutter specific to begin with.

I will definitely look into the StandardMessageCodec, as being able to return a map[] is exactly what I need. If I am able to have a map, then I can use that to fill out the data in my list. So that at least gets me pointed in the right direction.

Thanks again for your time, and especially your patience with all my questions. I have been all over the place language wise this year. I started with C# and Unity, then learning Python, then HCL for Terraform, Go, Node/JS, and now this. Things are just kind of mentally mushing together syntactically.

Anyways, you have been most helpful, I will leave you be now and continue researching and seeing what I can break, lol.

Thanks,
-MH

All 13 comments

Thanks for your interest in go-flutter:+1:!
go-flutter supports plugin (flutter <-> golang binding) wiki how to make a plugin.
Some plugins are already implemented checkout: go-flutter/plugins.

Thanks for the links. I want to make sure I am understanding this properly, it looks like the code in the plugin wiki is it's own separate complete project/app then? It is not something you code directly within your current project? I would have to create a whole new directory outside of my project, create desktop folder with new go code in it and then lib/dart files, and then reference that new separate project back from within my main project in order to just display some values?

Or is it possible to just implement the MethodChannel and async call directly in my project I have already been working on? While the ability to create plugins is great, I can't help but feel all of that is a bit overkill to just display some data. I mean, if that's how it has to be done, it's how it has to be done, I just wanted to confirm.

If you want to pass data from Go to the flutter front end plugins are the way to go!
But, If I understand your needs correctly you 'only' need to use flutter to display a config list. Thus the flutter app is only launched occasionally. If that's the case, a plugin is overkill.

Flutter/Dart can read your file directly, https://flutter.dev/docs/cookbook/persistence/reading-writing-files. There is no need to pass data from Go to the flutter front end, I am understanding your issue correctly?

For the most part, yes. The flutter side of things will only be displayed occasionally, such as when first configuring the application. I say "simply display the data", but in reality it is more complicated than that on the Go side, as I am using this package https://github.com/Unknwon/goconfig to open the file and parse the data in a specific way, but then later on the data will be used in other ways as I create more of the application. Displaying it was just the first step. Most things will be handled on the Go side, flutter would mostly be a way to take in text values and display some output or lists.

Essentially, I figured it would be a good learning experience to try to make a Rclone front end using this.

(This is just what I have thrown together so far yesterday and last night)

So far I just populated the list with hard coded values, but I really want to populate it with values I get from this:

(This was some of my initial test code that is working as I intended which reads/parses the rclone.conf file)

func Gclone() {
    config := struct {
        Section struct {
            Name string
        }
    }{}

    _ = confg.ReadFileInto(&config, ConfigPath)

    LoadConfig()
    cfg, sections := GetRemotes()
    for k, v := range sections {
        RMData[v] = &RemoteDataConfig{Name: v}
        secData, _ := cfg.GetSection(v)

        switch secData["type"] {
        case "drive":
            RMData[v] = SetupDrive(v, secData)
        }
        clientid, _ := cfg.GetValue(RMData[sections[k]].Name, "client_id")
        clientsecret, _ := cfg.GetValue(RMData[sections[k]].Name, "client_secret")
        fmt.Printf("Client_Id: %s : %s \n", clientid, clientsecret)
    }
}

func SetupDrive(name string, secData map[string]string) *RemoteDataConfig {
    return &RemoteDataConfig{
        Name: name, 
        Type: secData["type"], 
        Scope: secData["scope"], 
        Token: secData["token"], 
        ClientId: secData["client_id"], 
        ClientSecret: secData["client_secret"]}
}

So all said and done, for the time being, my plan was to try and get the data within RemoteDataConfig from SetupDrive() in the code above, and make it available to flutter so the list that is in the pic could be populated by the Name: from the RemoteDataConfig struct. So technically Flutter would just simply be displaying the name, but as you can see, it is a bit more complicated than that. So I guess I am just trying to figure out the best way to go about doing what I need to go for that.

On the flip side, the Flutter portion will have inputs on a config screen to take in text which Go will then save back to the config file, but I figured one step at a time.

There is 2 applications:
A rsync daemon.
A UI.

The rsync daemon should work independently from the UI.
The UI need to retrieve information from the rsync daemon.

Flutter plugin is a way of gaining access to platform specific feature. (And bundle those feature in the same exec).
Your rsync daemon should not contain any UI, flutter pluing shouldn't be use in the rsync daemon. The daemon should only expose a interface (through a TCP socket for example) on which any kind of UI could connect onto.
The TCP socket can be read from native dart code, no need for go-flutter plugins.

You could also bundle everything into a Flutter application. If so, flutter plugins is a better way to go.
It really comes down to architectural preferences.

I don't have a response for your question.
You can use go-flutter plugins.. or.. not!
It's up to you to make your choice.

I understand what you are saying. I am doing this as a personal learning project. I certainly know there are other ways to go about things, but that is not what I am after. The primary reason I am making this and running my Go application as a taskbar background application is to provide a scheduler/task runner to Rclone. My application will just run in the background and then issue commands to Rclone when it needs to.

I appreciate the information you have given. I will just have to experiment and see what I can come up with.

Thanks,
-MH

I hope I gave you the information you were looking for. If you have any questions/issues about the go-flutter package, fell free to ask them in gitter or on github!

Just in case anyone searches this in the future. I found this tutorial, you just have to translate the page, but it shows a good example of having a value on the Go side and then getting that value to display in your flutter app.

https://www.kikt.top/posts/flutter/desktop/go-desktop-engine/flutter-go-desktop-1/

Sorry to dig this back up again. I had a relevant question though on usage.

I implemented what I found in that tutorial and I was able to get a value from my Go code into the Flutter UI, but it is super... inconvenient? Is there a way to make this a bit more reusable?

Following the tutorial, it has you create a get_version_plugin.dart which contains:

import 'package:flutter/services.dart';

class GetVersionPlugin {
  static const _channel = const MethodChannel("top.kikt/go/version");

  static Future<String> get version async =>
      _channel.invokeMethod("getVersion");
}

Then to actually display it, I did similar to how they did it and created a new file (I had taken https://github.com/X-Wei/flutter_catalog and made it so it was a go-flutter application so I could see how things looked / worked on the desktop, so I reused some of its code, hence below having MyRoute and buildMyRouteContent. It works as you see it though and displays the value I have set in my Go code)

import 'package:flutter/material.dart';
import '../get_version.dart';
import '../route.dart';

class JobStatus extends MyRoute {
  const JobStatus([String sourceFile = 'lib/routes/tabs.dart'])
      : super(sourceFile);

  @override
  get title => 'Job Status';

  @override
  get links =>
      {'Doc': 'https://docs.flutter.io/flutter/material/TabBar-class.html'};

  @override
  Widget buildMyRouteContent(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: FutureBuilder<String>(
        future: GetVersionPlugin.version,
        builder: (c, snapshot) {
          if (!snapshot.hasData) {
            return Container();
          }
          return Text(snapshot.data);
        },
      ),
    );
  }
}

So all said and done, it takes that entire route/FutureBuilder to just display "v0.0.2".

In the image I posted above, the list is created via this:

  static final _items = <String>[
    'Google Drive' + GetVersionPlugin.version.toString(),
    'Google Cloud',
    'External USB Drive',

  ].map((item) => _ListItem(item, false)).toList();

Just to test, I tried what you see above, which though gave me "Instance of Future", so I assume it would not be as easy as calling the "GetVersion".

To use my prior code as the example, if in my Go code I wanted to use the plugin in a similar manner but I wanted to instead get the data from this function:

func SetupDrive(name string, secData map[string]string) *RemoteDataConfig {
    return &RemoteDataConfig{
        Name: name, 
        Type: secData["type"], 
        Scope: secData["scope"], 
        Token: secData["token"], 
        ClientId: secData["client_id"], 
        ClientSecret: secData["client_secret"]}
}

so that in my Flutter UI I could use it to display the contents of RemoteDataConfig, how would I have to change the FutureBuilder so that I can more readily access the data within it in other parts of the application and not just within this one particular page/route? As it stands, having to have a dedicated page for displaying the value isn't super useful, lol.

I implemented what I found in that tutorial and I was able to get a value from my Go code into the Flutter UI, but it is super... inconvenient? Is there a way to make this a bit more reusable?

Well, platform plugins are about implementing native platform code 1-2-3-4 times on multiples native languages (Java, Objective-C, CPP, Golang, ...). The platform code talks to a dart interface, _channel.invokeMethod for example, using different codecs StandardMessageCodec for example. Writing plugin isn't the most funnier exercise, but it fills a purpose that hybrid project like flutter/react-native/cordova cannot solves directly, because they cannot access native features.

Yes, plugins are inconvenient, and they are slow due to the serialization/deserialization/serialization overhead. But I don't agree with them not being reusable, the dart code is written once and can talk to a variety of native languages (We can found codec for: Java, Kotlin, Objective-C, Swift, CPP, Golang, Rust). Once the plugin is written, the user only sees a Future<Something> regardless of the platform. The Future<Something> looks exactly like a API call, it's consistent :+1:. To me, the plugin architecture of flutter is well designed (Coming from a Cordova background, it's refreshing to see a solution that dosn't feel like a hack), and does the job wonderfully.

If your question is about good Dart practices for handling API calls, I'm afraid I cannot answer that question since I'm a very bad Dart developer xD :face_with_head_bandage:

So all said and done, it takes that entire route/FutureBuilder to just display "v0.0.2".

I found that statement to be a bit silly, the plugin doesn't solves any platform related problem, and the way you use the string returned by the future is entirely up to you. If you don't want to use that entire route/FutureBuilder to just display "v0.0.2" than change the UI :stuck_out_tongue:. (again, how you handle the display of the string is out of the scope of go-flutter).

how would I have to change the FutureBuilder so that I can more readily access the data within it in other parts of the application and not just within this one particular page/route? As it stands, having to have a dedicated page for displaying the value isn't super useful, lol.

Well again I'm not a dart/flutter developer, go-flutter provides you a bridge between Golang and dart, the question is more about API handling.

go-flutter point:
If you want to send a RemoteDataConfig{} into Dart, look at StandardMessageCodec, you can return a map[interface{}]interface{} which will be converted to Dart Map

I appreciate the thorough reply. I do confess since Dart/Flutter in general is new to me, I suppose it was a bit difficult for me to differentiate what would be a go-flutter question and what would be a plain dart/flutter question. That is probably my biggest issue to overcome. Once I figure that out, it will probably help me to better locate more repos with code samples which are closer to what I am hoping to achieve. I tried to just use keywords from the tutorial to see if anything came up, but I suppose they were not related in the way I was expecting them to be.

Such as, I tried to look up "go-flutter" and "MethodChannel" since those were both things I used from the tutorial, hoping to see other people who have implemented it and what they were doing and how, but unfortunately that only yielded 7 results, and they were all from this repo, lol. Now I see that MethodChannel isn't / wasn't used along with anything go-flutter specific to begin with.

I will definitely look into the StandardMessageCodec, as being able to return a map[] is exactly what I need. If I am able to have a map, then I can use that to fill out the data in my list. So that at least gets me pointed in the right direction.

Thanks again for your time, and especially your patience with all my questions. I have been all over the place language wise this year. I started with C# and Unity, then learning Python, then HCL for Terraform, Go, Node/JS, and now this. Things are just kind of mentally mushing together syntactically.

Anyways, you have been most helpful, I will leave you be now and continue researching and seeing what I can break, lol.

Thanks,
-MH

Was this page helpful?
0 / 5 - 0 ratings

Related issues

lohnn picture lohnn  路  6Comments

Tokenyet picture Tokenyet  路  7Comments

kenthinson picture kenthinson  路  6Comments

ghost picture ghost  路  6Comments

Tcools picture Tcools  路  5Comments