Dart Package Tutorial – Getting Started
Learn how to create your first Dart package using test-driven development, generate documentation and publish it to pub.dev. By Agustinus Theodorus.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Dart Package Tutorial – Getting Started
25 mins
- Getting Started
- Understanding Dart Packages
- Dart Package vs. Flutter Plugin
- Knowing When to Create a Dart Package
- Writing Your First Dart Package
- Creating a Dart Package
- Understanding Dart Package Project Structure
- Test-Driven Development of the Dart Package
- Adding the Dependencies Through Terminal
- Importing Dependencies
- Dart Package Business Logic
- Exporting Your Dart Package
- Publishing Your Dart Package
- Creating the Basic Documentation README.md
- LICENSE
- Generating Package Documentation
- Importing Your Package Locally
- Publishing a Package Dry Run
- Publishing Dart Packages
- Importing Your Dart Package as Dependencies
- Where to Go From Here?
Often, there are features you want to include in your app, but writing the code can be tedious or difficult. So, you hop on to pub.dev and get the package that can help you add that feature, drastically saving your time and energy.
Packages help you extract the code you need so that it can be reused in the same or multiple apps. Packages are also a way you can contribute to the open source community.
Wouldn’t it be great to create your very own package and share it with the community? With this tutorial, you can! Along the way, you’ll learn how to:
- Create your first Dart package.
- Publish your package to pub.dev.
- Import your package into your Flutter app.
Getting Started
Start by clicking the Download Materials button at the top or bottom of the page to download the starter project.
In this tutorial, you’ll use Visual Studio Code, but you can also continue with Android Studio or IntelliJ IDEA. You’ll focus more on the Dart package development and end with integrating your package into your Flutter app (Android/iOS).
In the example, you’ll use Genderize.io, an Open API for predicting gender based on names.
Open your project in Visual Studio Code or Android Studio, and install your dependencies. In the terminal, type:
cd flutter
flutter pub get
Press Enter, and check the output:
$ cd flutter
$ flutter pub get
Running "flutter pub get" in flutter... 2,860ms
Build and run your project.
The app has an input field to enter a name and a button to genderize it. Enter the name Peter and tap Genderize.
As you see, you don’t get a result. This functionality is what you’ll implement later using your newly published Dart package.
Understanding Dart Packages
Dart packages are reusable code published on the Dart package registry. They function as libraries for Dart software development. But there are nuances between Dart packages, specifically those of Flutter as plugins.
Dart Package vs. Flutter Plugin
While both are technically Dart packages, a little nuance differentiates them.
As the name implies, Dart packages are made in pure Dart. You can use Dart packages for both Flutter and server-side Dart. Developing a Dart package is easier than a Flutter plugin because you don’t need to test any platform-specific code. Everything is in Dart!
On the other hand, Flutter plugins are pieces of code that function primarily as part of the mobile app. Flutter plugins usually wrap native Android/iOS code in a Dart package to reuse it within the Flutter app. In this tutorial, you’ll make a Dart package, so your package will be reusable within Flutter or simple Dart scripts.
Knowing When to Create a Dart Package
Flutter has a ton of packages for even the slightest of problems.
For example, if you want to create a native splash, Flutter has a native splash page package ready for you to use. Or, if you want to create launcher images, Flutter has a separate package for that too.
However, when you don’t find a suitable package for your needs, it’s usually because:
- You’re using a brand-new programming language with little community support.
- The problem is too technically expensive to implement — say, creating a new machine learning library.
- It’s a common problem that no one has created a plug-and-play solution for yet.
If you’re experiencing the last issue, you’ve found an excellent opportunity to create a new package and provide a solution to the wider community.
Writing Your First Dart Package
Before writing your Dart package, you must understand the API you’ll use. You’ll write a Dart API wrapper for Genderize.io, which predicts gender based on names. Users can submit names and get an approximate probability of that name’s gender.
The API accepts many parameters, but you’ll only use the name parameter.
Use this API directly to see how it works. Tap the link https://api.genderize.io/?name=peter:
{
"name": "peter",
"gender": "male",
"probability": 0.99,
"count": 165452
}
You see the results of calling this API. Now, you have to create a wrapper around it in Dart.
Creating a Dart Package
It’s finally time to create your first package. Open the terminal in the root of the starter project, and type:
dart create -t package genderizeio
Press Enter, and check the result:
$ dart create -t package genderizeio
Creating genderizeio using template package...
.gitignore
analysis_options.yaml
CHANGELOG.md
pubspec.yaml
README.md
example/genderizeio_example.dart
lib/genderizeio.dart
lib/src/genderizeio_base.dart
test/genderizeio_test.dart
Running pub get... 1.9s
Resolving dependencies...
Changed 46 dependencies!
Created project genderizeio in genderizeio! To get started, run the following commands:
cd genderizeio
dart run example/genderizeio_example.dart
You just created the package! This command uses the Dart template and prepares base package files for you. You must fill them with business logic.
The previous command’s output asks you to run a few more commands, so you’ll do that next. In the terminal, type the following commands:
cd genderizeio
dart run example/genderizeio_example.dart
Here is what’s going on in the commands above:
- Changed the working directory to your newly created package.
- Run the example project.
Press Enter to execute the commands.
$ dart run example/genderizeio_example.dart
awesome: true
You’ve just executed an example project. It has no special code, so you see the simple message awesome: true
. You’ll update this file later to run the Genderizeio package.
Understanding Dart Package Project Structure
The package’s core consists of the following files:
- lib/genderizeio.dart: Main interface file.
- lib/src/genderizeio_base.dart: Core business logic file. Everything under the lib/src folder is your private implementation and shouldn’t be imported by consumers directly. You have to export all public classes in the lib/genderizeio.dart file.
- pubspec.yaml: Dependencies and package metadata file.
- README.md, CHANGELOG.md: Supporting files and documentation.
- example/genderizeio_example.dart: The example that imports the library as if it were a package and tests whether the app is running.
- test/genderizeio_test.dart: For testing the core business logic.
Test-Driven Development of the Dart Package
You’ll use the test-driven development (TTD) process to implement your business logic. It means you must first write your tests. After that, you must write your code so that all the tests pass.
Since the package is an API wrapper, you’ll only do unit tests.
In testing, you will:
- Create a public interface,
GenderizeAPI
, to use the package. - Add the method
Future GenderizeAPI.send(String name) async
to call Genderize.io. - Return the object
Genderize
with the propertygender
in case of success or throw an exception in case of error.
Replace test/genderizeio_test.dart with the following code:
import 'package:genderizeio/genderizeio.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:test/test.dart';
import 'package:http/http.dart' as http;
import 'genderizeio_test.mocks.dart';
@GenerateMocks([http.Client])
void main() {
group('Genderize.io', () {
// 1
final client = MockClient();
// 2
final genderize = GenderizeAPI(client);
test('Peter is male', () async {
// 3
when(
client.get(Uri.parse('https://api.genderize.io?name=peter')),
).thenAnswer(
(_) async => http.Response(
'{"name":"peter","gender":"male","probability":0.99,"count":165452}',
200,
),
);
// 4
final result = await genderize.send('peter');
// 5
expect(result.gender, 'male');
});
// 6
test('API exception', () async {
when(
client.get(Uri.parse('https://api.genderize.io?name=')),
).thenAnswer(
(_) async => http.Response(
'{"error":"Missing \'name\' parameter"}',
500,
),
);
final result = genderize.send('');
await expectLater(
result,
throwsException,
);
});
});
}
You’ll see several code issues in the editor. That’s because you haven’t added the dependencies you’ve used. You’ll fix the errors soon by adding the dependencies and generating the mock data.
In the above code, you:
- Create an instance of mock
http.Client
. This class has mocked HTTP functions likeget
andpost
generated bybuild_runner
. - Create an instance of an API wrapper based on a mocked http client.
- Intercepte the network requests to return the mock data in tests.
- Call an API Wrapper with “Peter” as the name parameter.
- Test if Peter is male, with a result of “male”.
- Test to check whether the wrapper returns an exception in case of error.
Next, you’ll start fixing the errors in the above code.