flutter_using_packages
Flutter - Using Packages
Section titled “Flutter - Using Packages”Flutter’s power is significantly enhanced by its rich ecosystem of packages. Packages are bundles of shared code, similar to libraries or modules in other languages, created by the Flutter community and Google. They allow you to easily add pre-built functionality to your app, saving development time and effort.
Pub.dev: The Dart and Flutter Package Repository
Section titled “Pub.dev: The Dart and Flutter Package Repository”The central repository for Dart and Flutter packages is pub.dev. You can search for packages, view their documentation, check their popularity and health scores, and find installation instructions.
Types of Packages
Section titled “Types of Packages”Packages generally fall into these categories:
- Dart Packages: Written purely in Dart, containing utility functions, classes, or business logic. They don’t depend on the Flutter framework and can often be used in non-Flutter Dart projects as well. Example:
http(for making HTTP requests),intl(for internationalization). - Flutter Packages (or Plugin Packages): These packages depend on the Flutter framework and may include Dart code combined with platform-specific native code (Android/iOS/Web/Desktop) to access platform features. They often provide Flutter widgets or access to device capabilities.
-
- **Plugins:** Packages that specifically include platform-specific implementation using platform channels. Example: `camera` (accessing device camera), `shared_preferences` (accessing platform's simple storage), `webview_flutter` (embedding web views).
-
- **Pure Flutter Packages:** Packages that depend on Flutter but contain only Dart code, often providing custom widgets, state management solutions, or Flutter-specific utilities. Example: `provider` (state management), `cached_network_image` (advanced image loading).
Using a Package in Your Project
Section titled “Using a Package in Your Project”Adding a package to your Flutter project involves these steps:
1. Add the Dependency
Section titled “1. Add the Dependency”- Open your project’s
pubspec.yamlfile. - Under the
dependencies:section, add the package name and the desired version constraint. You can find the latest version and recommended constraint on pub.dev. - Common version constraints:
-
- `^version`: Allows updates to new minor and patch versions but not major versions (e.g., `^2.3.0` allows `2.3.1`, `2.4.0`, but not `3.0.0`). This is the most common and recommended constraint.
-
- `version`: Locks to an exact version.
-
- `any`: Allows any version (use with caution).
2. Install the Package
Section titled “2. Install the Package”-
From your project’s root directory in the terminal, run:
-
Most IDEs (VS Code, Android Studio) will automatically detect changes in
pubspec.yamland prompt you to runflutter pub getor run it for you.
3. Import the Package
Section titled “3. Import the Package”- In the Dart file where you want to use the package, add an
importstatement at the top, using thepackage:directive:
4. Use the Package
Section titled “4. Use the Package”- You can now use the classes, functions, and widgets provided by the imported package.
Developing Your Own Packages
Section titled “Developing Your Own Packages”You can also create your own packages to share code between projects or contribute to the community.
Creating a Package or Plugin
Section titled “Creating a Package or Plugin”-
Use the Flutter CLI:
-
This creates a standard package structure:
-
lib/: Contains the public Dart code.
-
lib/src/: Conventionally used for private implementation code.
-
pubspec.yaml: Defines the package.
-
README.md,CHANGELOG.md,LICENSE: Documentation and licensing.
-
example/: An optional example Flutter application demonstrating how to use the package.
-
android/,ios/, etc. (for plugins): Contain the native platform code.
Developing a Plugin (Brief Overview)
Section titled “Developing a Plugin (Brief Overview)”Developing a plugin involves:
- Defining the Dart API in the
lib/folder. - Implementing the communication logic using Platform Channels (
MethodChannel,EventChannel) in Dart. - Implementing the native counterparts on Android (Kotlin/Java) and/or iOS (Swift/Objective-C) that listen on the platform channel, execute the native code, and send results back.
Let’s refine the browser plugin example from the original tutorial content, assuming we created a plugin named my_browser.
Dart API (lib/my_browser.dart)
Section titled “Dart API (lib/my_browser.dart)”import 'dart:async';import 'package:flutter/services.dart';
class MyBrowser { // Define the channel name consistently static const MethodChannel _channel = MethodChannel('com.example.my_browser/channel');
// Method to open the browser Future<void> openBrowser(String urlString) async { try { // Invoke the 'openBrowser' method on the native side await _channel.invokeMethod('openBrowser', {'url': urlString}); } on PlatformException catch (e) { print("Failed to open browser: '${e.message}'."); // Consider re-throwing or handling the error appropriately } }
// Example: Platform version (often included in template) static Future<String?> get platformVersion async { final String? version = await _channel.invokeMethod('getPlatformVersion'); return version; }}Android Implementation (android/src/.../MyBrowserPlugin.kt)
Section titled “Android Implementation (android/src/.../MyBrowserPlugin.kt)”package com.example.my_browser // Adjust package name
import androidx.annotation.NonNullimport io.flutter.embedding.engine.plugins.FlutterPluginimport io.flutter.plugin.common.MethodCallimport io.flutter.plugin.common.MethodChannelimport io.flutter.plugin.common.MethodChannel.MethodCallHandlerimport io.flutter.plugin.common.MethodChannel.Resultimport io.flutter.embedding.engine.plugins.activity.ActivityAwareimport io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
// Required importsimport android.app.Activityimport android.content.Intentimport android.net.Uri
class MyBrowserPlugin: FlutterPlugin, MethodCallHandler, ActivityAware { private lateinit var channel : MethodChannel private var activity: Activity? = null // Hold activity reference
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { channel = MethodChannel(flutterPluginBinding.binaryMessenger, "com.example.my_browser/channel") channel.setMethodCallHandler(this) }
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { if (call.method == "getPlatformVersion") { result.success("Android ${android.os.Build.VERSION.RELEASE}") } else if (call.method == "openBrowser") { val url = call.argument<String>("url") if (url != null) { openBrowser(url, result) } else { result.error("INVALID_ARGUMENT", "URL cannot be null", null) } } else { result.notImplemented() } }
private fun openBrowser(url: String, result: Result) { if (activity == null) { result.error("NO_ACTIVITY", "Cannot open browser without a foreground activity.", null) return } try { val intent = Intent(Intent.ACTION_VIEW) intent.data = Uri.parse(url) activity?.startActivity(intent) result.success(true) // Indicate success } catch (e: Exception) { result.error("FAILED", "Could not open browser: ${e.message}", null) } }
override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { channel.setMethodCallHandler(null) }
// ActivityAware methods override fun onAttachedToActivity(binding: ActivityPluginBinding) { activity = binding.activity }
override fun onDetachedFromActivityForConfigChanges() { activity = null }
override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) { activity = binding.activity }
override fun onDetachedFromActivity() { activity = null }}Note: The Android implementation uses the newer FlutterPlugin and ActivityAware interfaces for better lifecycle management compared to the older Registrar approach.
iOS Implementation (ios/Classes/MyBrowserPlugin.swift)
Section titled “iOS Implementation (ios/Classes/MyBrowserPlugin.swift)”The iOS implementation would be similar to the one shown in the Platform Channels chapter, adapted to the plugin structure.
Using a Local Package
Section titled “Using a Local Package”To use a package you are developing locally (before publishing), you can reference it using a path dependency in the pubspec.yaml of the app using it:
dependencies: flutter: sdk: flutter my_browser: # Your local package name path: ../my_browser # Relative path to the package directoryPackages are fundamental to efficient Flutter development, leveraging community contributions and enabling code reuse.
Always check package licenses and evaluate their maintenance status and compatibility before adding them to your project.