The Road to Enhanced Flutter Development Part 1

The Road to Enhanced Flutter Development Part 1

ยท

4 min read

Introduction

Flutter is an excellent open-source framework for building cross-platform applications in a single codebase, ensuring good performance. This series documents my journey of building a good dev tool app for Flutter apps. Of course, it will be open source โœจ

Problem

One issue that many developers face is the lack of extension support for the Flutter dev tools. There is an open issue and discussion regarding this on https://github.com/flutter/devtools/issues/1632, which was created in February 2020. Hopefully, it will be merged soon.

I plan to develop a standalone dev tool app for Flutter that will allow for awesome features, such as viewing the shared preferences state of the app or checking the state of the app, among many others.

Solution

I have been considering the idea of creating a standalone Flutter development tool for building common, useful tooling that would greatly assist developers during the development process. Initially, I would like to focus on basic tooling capabilities, such as the ability to visualise the shared_preferences state, inspect classes, and more.

Long term vision

This dev tool is designed to take your developer experience to the next level. With the ability to integrate multiple plugins, you can easily customise the options on the dev tool per project level. This means you can have a unique development experience tailored to your specific needs.

But that's not all. With the ability to add custom commands, you can further enhance your workflow. For example, imagine having a button to sign in to the app. All you need to do is provide the code for it, and with a click of a button, you'll be signed in. It's that simple.

Current progress

I haven't really thought about a name for it yet, but for now I'm calling it "Flutter Ninja." However, I may change the name in the future. ๐Ÿคž

๐Ÿ•ต๏ธโ€โ™€๏ธ Mode

I've been exploring how the Flutter dev tools work. It turns out they use the vm_service package to connect to a running Flutter application and communicate with it.

You may have seen this many times while running a Flutter application. Have you ever wondered what it is? ๐Ÿค”

Dev tools connected machine

This is the Dart VM Service Protocol. It is used to communicate with a running Dart Virtual Machine.

The methods and other important information are documented in detail here. I have been exploring it and received some advice from Norbert ๐Ÿ™Œ.

This is the current progress, I have connected to an flutter application that I have

Shared Preferences

P.S: Ignore the blurred part as it contains confidential information that cannot be shown. Additionally, there was no need to use a random app and create dummy values just to prove that this is a functional tool ๐Ÿซก

The how

To begin, connect to the vm_service client using the vmConnectUri method.

After establishing the connection, retrieve the main isolate of the running Flutter application.


Future<Isolate?> getIsolate() async {
  final isolates = vm.isolates ?? [];
  if (isolates.isEmpty) {
    return null;
  }

  for (var isolate in isolates) {
    log('Isolate: ${isolate.name}');
  }

  log('Isolates found: ${isolates.length}');

  isolate = await vmService.getIsolate(isolates.first.id!);

  return isolate;
}

To recognise the main isolate, we can rely on isolate.name. The name of the main isolate is ๐Ÿฅ Main. However, typically, the first isolate is the Main one, which we can use to identify it.

To obtain a list of all available classes, use the getClassList method with the isolateId parameter, which we obtained earlier.

Once you have this list, you can use the getInstances method to retrieve the instances.

The Instance is one of the most useful class, it has many important details with it, you can find them all here, but predominately we would need valueAsString, elements and associations

TL;DR

  • valueAsString - when the return type is bool, int, string , double

  • elements - when the return type is List or Set

  • associations - when the return type is Map

Evaluate

This is the method that does the magic ๐Ÿช„, it takes in expression executes it and returns the result.

Example

If the expression is 1+1 the evaluated result will be 2 as string.

Class A {
    bool doMagic() {
        return true;
    }
}

For example we have an instance of a class A

we evaluate the expression doMagic the result would be true in string format.

This is the snippet from the repository that helped me achieve it!

Future<Instance?> evaluate({required String targetId, required String expression}) async {
  final Response result = await vmService.evaluate(isolate.id!, targetId, expression);
  return await getObjectFromResult(result.json?['id']);
}

Future<Instance?> getObjectFromResult(String resultId) async {
  final result = await vmService.getObject(isolate.id!, resultId);
  final Instance? instance = result as Instance?;

  return instance;
}

Next Steps?

Stay Engaged for What's Next!

This journey has just begun, with Part 1 being the first glimpse into our vision. In the upcoming post, we'll delve deeper, exploring how we seamlessly integrated SharedPreferences state into our powerful dev tool, along with a host of other intriguing details.

Moreover, the repository for this project will be thoroughly cleaned and made open-source, paving the way for you to join me in shaping its future. Be sure to follow me on GitHub at github.com/Rohithgilla12 so you won't miss the moment the repository goes live. Together, we're set to embark on an exciting development journey.

Stay tuned! ๐Ÿš€๐Ÿ™Œ

Resources

vm_service

VM Service Docs