Hosted URL : https://web.flatteredwithflutter.com/#/
We will cover briefly about
- Using Dart FFI
- Fetch login history of a user (macOS)
- Create a CLI App
Article here: https://flatteredwithflutter.com/dart-ffi-cli-dart2native/
Note: We won’t be explaining in-depth about Dart FFI as there are good articles dedicated to it.
- Using Dart FFI
FFI: (Foreign Function Interface) can be used to call the C/C++ language-based APIs
A statically linked library is embedded into the app’s executable image and is loaded when the app starts.
Symbols from a statically linked library can be loaded using DynamicLibrary.executable
or DynamicLibrary.process
.
A dynamically linked library is distributed in a separate file or folder within the app and loaded on-demand. A dynamically linked library can be loaded into Dart via DynamicLibrary.open
.
How will we approach?
For this article, we will be utilizing the dynamic system library.
In case you want to create your own dynamic library, read this.
2. Fetch login history of a user (macOS)
Open the terminal and type this command
last login `username` where username is before @ [username@Macbook-Pro]
- You should get your login history. Our goal is to call this command from Dart.
- This command is defined in a system dynamic library, present in the macOS.
In macOS, the system libraries are present in
/usr/lib/libSystem.dylib
For getting paths for different OS, visit here.
We will load our dynamic library, specified at the path above, in Dart.
- Import the dart ffi package(present inside Flutter) as
import 'dart:ffi' as ffi
This has a class DynamicLibrary. We call the method open and load our dynamic library (Dylibs.systemDyLib).
class Dylibs { static const String systemDyLib = '/usr/lib/libSystem.dylib'; static const String systemSymbolName = 'system'; }
Each dynamic library is composed of symbols. For finding the symbols in a library refer here.
Now, getting the user login history falls under the symbol System.
- Lookup for the symbol from the loaded dynamic library using lookupFunction.
We have specified SystemC and SystemDart functions, which basically are
// C header typedef: typedef SystemC = ffi.Void Function(ffi.Pointer<Utf8> command); // Dart header typedef typedef SystemDart = void Function(ffi.Pointer<Utf8> command);
This combines the lookup function and casts to a Dart function.
- Next, we convert the command (our last login command) into something which C understands using
/// Convert a [String] to a Utf8-encoded null-terminated C string. /// Returns a malloc-allocated pointer to the result. final cmd = Utf8.toUtf8(command);
- Run the command using
sysFunc(cmd)
- Finally, free up the memory, since C/C++ don’t have garbage collection
Create a CLI App
We will create our own command, which would have info and description regarding the CLI App.
- Create our command
We use the CommandRunner, and define our command(last_login) with some description as
- Add our last login Command. In order to create your own commands, you need to extend Command Class
// THIS ADDS OUR LAST LOGIN COMMAND
runner.addCommand(LastLoginCmd());
Note: LastLoginCmd is our custom class
WE create an abstract base command class and declare the methods.
abstract class BaseCLICommand extends Command{ String loadingMessage; void execCommand(String arg); @override Future run() async { if (argResults.arguments.isEmpty) { throw Exception('😳😳 Please specify the argument'); } final arg = argResults.arguments.first; final loadingMsg = '$loadingMessage $arg'; stdout.write('$loadingMsg\n'); execCommand(arg); } }
- argResults.arguments help us in fetching the user input.
- stdout.write is used to print out to the console.
- execCommand is the function, which the extended class defines.
Our LastLoginCmd extends the above class and implements the methods.
- After we add the command as above
// THIS ADDS OUR LAST LOGIN COMMAND
runner.addCommand(LastLoginCmd());
Finally, we run this command as
runner.run(args);
Last Step (Convert to CLI App)
We utilize the power of
dart2native
, which has the ability to compile Dart programs to self-contained executables. With dart2native, you can create tools for the command line on macOS, Windows, or Linux using Dart.
- Navigate to the directory containing your dart entry point. For instance
My directory will be lib/ffi
2. Run the command
dart2native cmd_line.dart -o login_history
-o <path>
or --output=<path>
Generates the output.
This creates our CLI App named login_history.
Final Output
Hosted URL : https://web.flatteredwithflutter.com/#/
Top comments (0)