Preface
There are two concepts of package and plug-in in flutter
. Plug-in is package
a kind of . Its full name is plugin package
, we call it abbreviated as plugin
plug-in in Chinese. Package ( Package
) mainly refers to flutter
the encapsulation of related functions, similar to Android
the plug-ins in and iOS
the third-party libraries in . The plug-in ( Plugin
) mainly refers to calling native functions through plug-ins, such as obtaining basic information of the mobile phone, obtaining the native camera, etc. There is still a certain difference between the two. Package
Generally, it only contains Dart
code, while the plug-in not only contains Dart
, but also contains native languages, such as Java
or in Android Kotlin
, or iOS
in Objective-C
and Swift
. Package
Hedu Plugin
is designed to encapsulate some basic components, business components, etc., to achieve component development, so that implementation functions can be quickly introduced when used in many places in the project.
- Packages
Dart package
require at least onepubspec.yaml
file and usually alib
directory.pubspec.yaml
The file is a metadata file used to define the package name, version number, author and other information;lib
the directory contains shared code, which contains at least one<package-name>.dart
file. Onepackage
can contain dependencies (pubspec.yaml
declared in files), Dart libraries, applications, resources, fonts, tests, images, examples, etc. There are many packages listed on pub.dev , developed and released by Google engineers and developers in the Flutter and Dart communities, that you can use in your own applications.- Plugins
(plugin package
) are a special kind of package, specifically those that help you get native platform features. Plugins can be written for Android (using Kotlin or Java), iOS (using Swift or Objective-C), Web, macOS, Windows, Linux, or any combination thereof. For example: a plug-in can provide Flutter applications with the function of using the camera of the native platform.
Let’s take a look at how to develop Package and Plugin
1. Package
1.1 Create Package
Create using command line:
flutter create --template=package hello
This will hello
create a package
project in the directory with the following content:
The LICENSE file
will most likely be an empty license file.The unit test file of the test/hello_test.dart file
Package .hello.iml file
Configuration file generated by IntelliJ..gitignore file A
hidden file that tells the Git system which files or folders should be hidden..metadata file
is a hidden file used by the IDE to record the properties of a Flutter project.The pubspec.yaml file
is a file in yaml format that the pub tool needs to use and contains package dependencies.README.md file
is a starting document used to describe the package.
The Dart implementation code of the lib/hello.dart file package..idea/modules.xml and .idea/workspace.xml files are
the respective configuration files of IntelliJ (contained under the .idea hidden folder).CHANGELOG.md file
is another probably empty document used to record package version changes.
It is recommended to use Android Studio
to create, open Android Studio
the selection New Flutter Project
, first you need to select the one you want package
to use flutter sdk
:
Then you need to enter the plug-in name, file directory, plug-in type (you can choose Yes Package
or Plugin
), supported development platform and corresponding development language:
Here, enter the project name flutter_package_demo
, and then Project type
select Package
. For the time being, only select , for the platform Android
, iOS
and select the corresponding development language kotlin
. Swift
After creating the project, the directory structure is as follows:
Package
The directory structure of the project is relatively simple. It mainly consists of lib
classes with the same name as the project in the directory flutter_package_demo.dart
. This class is mainly used to expose the classes in the package so that other projects can call them. Package
The code implementation in lib
can be placed in the directory, and the test code can be written in test
the directory flutter_package_demo_test.dart
.
Because Package
it is a simple Dart
library and does not have Android
a iOS
shell project, it cannot be run directly for joint debugging testing. You can introduce it Package
through local dependencies in your own project , and then call it in the project for testing and joint debugging.path
Package
1.2 Define Package
After creating the project here, the template code flutter_package_demo.dart
has generated a method in:
library flutter_package_demo;
/// A Calculator.
class Calculator {
/// Returns [value] plus 1.
int addOne(int value) => value + 1;
}
This library flutter_package_demo
indicates that it package
is a dependent package, and the name of the package isflutter_package_demo
1.3 Verify Package
Since the page UI is not involved here, this logic can be verified directly in the unit test, and the code is written in test
the directory flutter_package_demo_test.dart
:
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter_package_demo/flutter_package_demo.dart';
void main() {
test('adds one to input values', () {
final calculator = Calculator();
expect(calculator.addOne(2), 3);
expect(calculator.addOne(-7), -6);
expect(calculator.addOne(0), 1);
});
}
Then start the unit tests:
If it is a package involving UI, when testing locally, you can directly create a directory under the current project and develop function verification code in it, or introduce the package example
in an externally used project through the following methods :pubspec.yaml
flutter_package_demo:
path: ../ # package 所在的路径,绝对或者相对
1.4 Package containing UI
Let's transform the project and provide a definition package
that can be displayed externally :material dialog,
package
library flutter_package_demo;
export 'caculator.dart';
export 'dialogs.dart';
The package name remains unchanged, the logic code is removed, and two files are exported. The first is the extraction of the above-mentioned plus 1 method, and the second is what we want to display dialog
:
import 'package:flutter/material.dart';
import 'dialog_widget.dart';
class Dialogs {
static const TextStyle titleStyle =
TextStyle(fontWeight: FontWeight.bold, fontSize: 16);
static const Color bcgColor = Color(0xfffefefe);
static const Widget holder = SizedBox(
height: 0,
);
static const ShapeBorder dialogShape = RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(16)));
static const ShapeBorder bottomSheetShape = RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(16), topRight: Radius.circular(16)));
/// 屏幕中弹出对话框
static Future<void> materialDialog({
required BuildContext context,
Function(dynamic value)? onClose,
String? title,
String? msg,
List<Widget>? actions,
Widget customView = holder,
bool barrierDismissible = true,
Color? barrierColor = Colors.black54,
String? barrierLabel,
bool useSafeArea = true,
bool useRootNavigator = true,
RouteSettings? routeSettings,
ShapeBorder dialogShape = dialogShape,
TextStyle titleStyle = titleStyle,
TextStyle? msgStyle,
TextAlign? titleAlign,
TextAlign? msgAlign,
Color color = bcgColor,
double? dialogWidth,
}) async {
await showDialog(
context: context,
barrierDismissible: barrierDismissible,
barrierColor: barrierColor,
barrierLabel: barrierLabel,
useSafeArea: useSafeArea,
useRootNavigator: useRootNavigator,
routeSettings: routeSettings,
builder: (context) {
return Dialog(
backgroundColor: color,
shape: dialogShape,
child: DialogWidget(
title: title,
dialogWidth: dialogWidth,
msg: msg,
actions: actions,
customView: customView,
titleStyle: titleStyle,
msgStyle: msgStyle,
titleAlign: titleAlign,
msgAlign: msgAlign,
color: color,
),
);
},
).then((value) => onClose?.call(value));
}
/// 底部弹出对话框
static void bottomMaterialDialog({
required BuildContext context,
Function(dynamic value)? onClose,
String? title,
String? msg,
List<Widget>? actions,
Widget customView = holder,
bool barrierDismissible = true,
ShapeBorder dialogShape = bottomSheetShape,
TextStyle titleStyle = titleStyle,
TextStyle? msgStyle,
Color color = bcgColor,
bool isScrollControlled = false,
bool useRootNavigator = false,
bool isDismissible = true,
bool enableDrag = true,
RouteSettings? routeSettings,
AnimationController? transitionAnimationController,
}) {
showModalBottomSheet(
context: context,
shape: dialogShape,
backgroundColor: color,
isScrollControlled: isScrollControlled,
useRootNavigator: useRootNavigator,
isDismissible: isDismissible,
enableDrag: enableDrag,
routeSettings: routeSettings,
transitionAnimationController: transitionAnimationController,
builder: (context) => DialogWidget(
title: title,
msg: msg,
actions: actions,
customView: customView,
titleStyle: titleStyle,
msgStyle: msgStyle,
color: color,
),
).then((value) => onClose?.call(value));
}
}
Then add example
a project to verify ours . For the sake of simplicity, we will not add a project dialog
here as an example. The project structure is as follows:Android
iOS demo
Create and write function verification code in example
the project lib
directory :main.dart
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_package_demo/caculator.dart';
import 'package:flutter_package_demo/dialogs.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'package 测试',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: SafeArea(
child: Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: const Text("package 测试"),
),
body: const HomePage()),
));
}
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int value = 0;
@override
Widget build(BuildContext context) {
return Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(value.toString(), textScaleFactor: 1.5),
ElevatedButton(
onPressed: () {
setState(() {
value = Calculator().addOne(value);
});
},
child: const Text('+1')),
showPackageDialog(context),
],
),
);
}
Widget showPackageDialog(BuildContext context) {
return MaterialButton(
color: Colors.grey[300],
minWidth: 300,
onPressed: () => Dialogs.materialDialog(
msg: '确认关闭?',
title: "关闭",
color: Colors.white,
context: context,
dialogWidth: kIsWeb ? 0.3 : null,
onClose: (value) => debugPrint("返回值: '$value'"),
actions: [
ElevatedButton(
onPressed: () {
Navigator.of(context).pop(['取消了', 'List']);
},
child: const Text('取消', style: TextStyle(color: Colors.black)),
),
OutlinedButton(
onPressed: () {
Navigator.of(context).pop(['关闭了', 'List']);
},
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.red)),
child: const Text('关闭', style: TextStyle(color: Colors.white)),
),
]),
child: const Text("Show Material Dialog"),
);
}
}
The page effect is as follows:
2. Plugin
Plugin
Package
The biggest difference between and is Plugin
that you can access the capabilities provided by native and cross-platform API
, and then call the functions of native Android
and iOS
through plug-ins to achieve certain functions or better user experience, such as obtaining mobile phone version information, calling native cameras, etc. The code includes Dart
, Android
Native code, iOS
native code.
2.1 Create Plugin
Similar to creation Package
, you can also use the command line to create:
flutter create --org com.example --template=plugin --platforms=android,ios -a kotlin hello
flutter create --org com.example --template=plugin --platforms=android,ios -a java hello
flutter create --org com.example --template=plugin --platforms=android,ios -i objc hello
flutter create --org com.example --template=plugin --platforms=android,ios -i swift hello
4 instructions, you can freely choose one of them according to the selected plug-in platform and development language, which will hello
create a plug-in project in the directory, which contains the following content:
The lib/hello.dart file
Dart plug-in API implementation.The android/src/main/java/com/example/hello/HelloPlugin.kt file implements the native plug-in API of the Android platform (using the Kotlin programming language).
The ios/Classes/HelloPlugin.m file
implements the native plug-in API of the iOS platform (using Objective-C programming language).example/ file
A Flutter app that depends on the plugin and explains how to use it.By default, the iOS code in the plug-in project is written in Swift, and the Android code is written in Kotlin.
To add support for a specific platform to an existing plugin project, run flutter create
the command in the project directory and add it --template=plugin
. For example, to add web support to an existing plug-in project, run the following command:
flutter create --template=plugin --platforms=web .
It is recommended to use an IDE for creation, which is more intuitive and easy to operate.
1. First open Android Studio
, then click File->New->New Flutter Project
.
2. Enter the selection flutter sdk
page, select your local one flutter
, and then click next
.
3. Select Plugin type
as shown below.
The first few steps Package
are the same as creation, the only difference is the third step, here Project type
selectPlugin
Click create
to create a project. The project structure is as follows:
lib
The files in the directory are flutter
the specific implementation of the plug-in and example
are plug-in test projects that can be used for plugin
functional testing. The directory is the end-native implementation iOS
of the plug-in . The directory is the end -native implementation of the plug-in . The directory is the unit test corresponding to the plug-in.iOS
android
Android
test
2.2 Define Plugin
Here we first focus on lib
the three files in the directory:
- Interface definition
flutter_plugin_demo_platform_interface.dart
: Where the interface is defined, this file only defines methods. getPlatformVersion()
As a method that is automatically generated when creating a project, here we add a new getScreenWidth()
method to get the screen width:
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
import 'flutter_plugin_demo_method_channel.dart';
abstract class FlutterPluginDemoPlatform extends PlatformInterface {
/// Constructs a FlutterPluginDemoPlatform.
FlutterPluginDemoPlatform() : super(token: _token);
static final Object _token = Object();
static FlutterPluginDemoPlatform _instance = MethodChannelFlutterPluginDemo();
/// The default instance of [FlutterPluginDemoPlatform] to use.
///
/// Defaults to [MethodChannelFlutterPluginDemo].
static FlutterPluginDemoPlatform get instance => _instance;
/// Platform-specific implementations should set this with their own
/// platform-specific class that extends [FlutterPluginDemoPlatform] when
/// they register themselves.
static set instance(FlutterPluginDemoPlatform instance) {
PlatformInterface.verifyToken(instance, _token);
_instance = instance;
}
Future<String?> getPlatformVersion() {
throw UnimplementedError('platformVersion() has not been implemented.');
}
Future<String?> getScreenWidth() {
throw UnimplementedError('getScreenWidth() has not been implemented.');
}
}
- Interface implementation
The interface implementation is mainly in flutter_plugin_demo_method_channel
the file. This file is the above-mentioned interface
subclass and is responsible for the implementation of the specific interface. However, the specific implementation of the method depends on the implementation of the calling native end.
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'flutter_plugin_demo_platform_interface.dart';
/// An implementation of [FlutterPluginDemoPlatform] that uses method channels.
class MethodChannelFlutterPluginDemo extends FlutterPluginDemoPlatform {
/// The method channel used to interact with the native platform.
@visibleForTesting
final methodChannel = const MethodChannel('flutter_plugin_demo');
@override
Future<String?> getPlatformVersion() async {
final version = await methodChannel.invokeMethod<String>('getPlatformVersion');
return version;
}
@override
Future<String?> getScreenWidth() async {
final screenWidth = await methodChannel.invokeMethod<String>('getScreenWidth');
return screenWidth;
}
}
The implementation here getScreenWidth
requires methodChannel
calling native methods.
- transfer
The class with plugin
the same name as the project flutter_plugin_demo.dart
is mainly for external calls. This class provides all methods for external calls. The methods provided by this class include two types, one is directly implemented using Dart, and the other is implemented by relying on the native side and calling flutter_plugin_demo_platform_interface
methods in the interface class.
import 'flutter_plugin_demo_platform_interface.dart';
class FlutterPluginDemo {
Future<String?> getPlatformVersion() {
return FlutterPluginDemoPlatform.instance.getPlatformVersion();
}
Future<String?> getScreenWidth() {
return FlutterPluginDemoPlatform.instance.getScreenWidth();
}
// 直接 dart 实现
int getScreenHeight() {
return 1080;
}
}
2.3 iOS native implementation
iOS
The directory is mainly implemented for the iOS native side. Here you can use the project example
under it iOS
for debugging. Since the project has no pod
files by default, you need to do it example
under the directory .iOS
pod install
What needs to be noted here is that the language is selected when creating the project Swift
, so the specific implementation is in swift
the class. If yes is selected oc
, the implementation is in oc
the class. In fact swift
, the implementation is also oc
called through the class swift
.
FlutterPluginDemoPlugin.m
You can see that the call is made in the class , SwiftFlutterPluginDemoPlugin.swift
and the specific implementation is in the class:
#import "FlutterPluginDemoPlugin.h"
#if __has_include(<flutter_plugin_demo/flutter_plugin_demo-Swift.h>)
#import <flutter_plugin_demo/flutter_plugin_demo-Swift.h>
#else
// Support project import fallback if the generated compatibility header
// is not copied when this plugin is created as a library.
// https://forums.swift.org/t/swift-static-libraries-dont-copy-generated-objective-c-header/19816
#import "flutter_plugin_demo-Swift.h"
#endif
@implementation FlutterPluginDemoPlugin
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
[SwiftFlutterPluginDemoPlugin registerWithRegistrar:registrar];
}
@end
SwiftFlutterPluginDemoPlugin
Implemented in class:
import Flutter
import UIKit
public class SwiftFlutterPluginDemoPlugin: NSObject, FlutterPlugin {
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "flutter_plugin_demo", binaryMessenger: registrar.messenger())
let instance = SwiftFlutterPluginDemoPlugin()
registrar.addMethodCallDelegate(instance, channel: channel)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
switch call.method {
case "getScreenWidth":
let screenRect = UIScreen.main.bounds
let screenWidth = screenRect.size.width
let screenHeight = screenRect.size.height
result("iOS \(screenWidth)")
case "getPlatformVersion":
result("iOS " + UIDevice.current.systemVersion)
default:
result("no such method !")
}
}
}
2.4 Android native implementation
Because the language selected when creating the project is kotlin
, the Android
native implementation is in a file kotlin
with the same name as the project in the directory FlutterPluginDemoPlugin.kt
:
package com.example.flutter_plugin_demo
import android.content.Context
import androidx.annotation.NonNull
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
/** FlutterPluginDemoPlugin */
class FlutterPluginDemoPlugin: FlutterPlugin, MethodCallHandler {
/// The MethodChannel that will the communication between Flutter and native Android
///
/// This local reference serves to register the plugin with the Flutter Engine and unregister it
/// when the Flutter Engine is detached from the Activity
private lateinit var channel : MethodChannel
private var context: Context? = null
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "flutter_plugin_demo")
context = flutterPluginBinding.applicationContext
channel.setMethodCallHandler(this)
}
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
when (call.method) {
"getPlatformVersion" -> result.success("Android ${android.os.Build.VERSION.RELEASE}")
"getScreenWidth" -> result.success("Android ${context?.resources?.displayMetrics?.widthPixels}")
else -> result.notImplemented()
}
}
override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
channel.setMethodCallHandler(null)
}
}
2.5 Functional verification
After completing the above steps, our plug-in is developed. Next, let us example
verify the plug-in we just developed in the project and example/lib/main.dart
write the test code in:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_plugin_demo/flutter_plugin_demo.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _platformVersion = 'Unknown';
String _screenWidth = 'Unknown';
final _flutterPluginDemoPlugin = FlutterPluginDemo();
@override
void initState() {
super.initState();
initPlatformState();
_getScreenWidth();
}
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initPlatformState() async {
String platformVersion;
// Platform messages may fail, so we use a try/catch PlatformException.
// We also handle the message potentially returning null.
try {
platformVersion = await _flutterPluginDemoPlugin.getPlatformVersion() ??
'Unknown platform version';
} on PlatformException {
platformVersion = 'Failed to get platform version.';
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
_platformVersion = platformVersion;
});
}
Future<void> _getScreenWidth() async {
String screenWidth;
try {
screenWidth = await _flutterPluginDemoPlugin.getScreenWidth() ?? '0';
} on PlatformException {
screenWidth = 'Failed to get screen width.';
}
if (!mounted) return;
setState(() {
_screenWidth = screenWidth;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: Column(
children: [
Center(
child: Text('Running on: $_platformVersion\n',textScaleFactor: 1.5),
),
Center(
child: Text('screen width: $_screenWidth\n',textScaleFactor: 1.5),
),
],
),
),
);
}
}
Final page effect:
3. Release
There are two main types of publishing, one is to publish to Flutter's official website , and the other is to publish to your own company's private library. Most of the publishing steps for both are the same, but there are differences in some places. Here are the two The publishing method is introduced.
3.1 Preparation before release
First, you need to check whether Package
or Plugin
contains the four files pubspec.yaml
, README.md
, CHANGELOG.md
, and the completeness needs to be checked. LICENSE
These four contents will be present by default when creating them. If they are missing, you can run them in the project terminal flutter create .
to complete them (note that there is a dot).
- pubspec.yaml
This file mainly refers to external plug-ins. Among them name
, , description
, version
need homepage
to be filled in completely, publish_to
which means publishing the library to the specified location. It is required to publish to a private library, but pub.dev
not required if it is published to.
- README.md
This file is mainly used to write the content of the plug-in or package, so that others can be informed of the function of the library when viewing it.
- CHANGELOG.md
This file mainly records the version modification record of the plug-in or package, describing the update content of each version.
- LICENSE
This file is mainly to add the license certificate, which can be filled in as needed.
After the above preparations are completed, you need to verify the project, open the terminal, enter the path of the plug-in or package, and then run
flutter packages pub publish --dry-run
Then check the running results. If the warning message is 0, it means there is no problem and you can publish it.
3.2 Release
After the verification is completed, you can publish it. It is better to use the command line. It is best to surf the Internet scientifically first, and then run the command to publish:
flutter packages pub publish
There is a difference between publishing to the official and private libraries. If you publish to the official, after running the command, there will be an extra step to log in to the Google account verification, but publishing to the private library does not require it.
To publish to a private library, you need to build a private warehouse. There are many tutorials on the Internet, you can refer to the following: Building a Flutter private warehouse
Notice:
Developers who have set up Chinese mirrors cannot (and should not) upload packages to the currently existing mirrors. If you set up a mirror, executing the above publishing code may cause publishing to fail. After the network is set up, there is no need to cancel the Chinese image. You can upload it directly by executing the following code:
flutter pub publish --server=https://pub.dartlang.org
4. Use
4.1 Depend on the package package of pub.dev warehouse
cupertino_icons: ^1.0.2
4.2 Depend on the package package of the remote git repository
flutter_plugin_name:
git:url: https://github.com/xxxxxx/xxxxxx.git #git warehouse address
path: xxxxx #If the project is not in the root directory of the git address, you need to specify the path
ref: '1.0.0' #The specified version corresponds to the tag tag in the git warehouse and you can also specify a branch ref: some-branch
4.3 Packages that depend on private pub repositories
flutter_plugin_name:
hosted:
name: flutter_plugin_name
url: https://xxxxxversion:1.0.3
4.3 Packages that depend on local warehouses
flutter_plugin_name:
path: ../ #Can be a relative path or an absolute path
5. Others
When creating the project, we found that there are several other types to Project type
choose from: Application
Everyone is familiar with it. It is a pure flutter
project with the main body Flutter
. Of course, it can also be accessed Android Module
or iOS Framework
contain Android and iOS projects internally. Plugin
, Package
has been introduced above, let’s briefly look at the remaining types
5.1 Module
Project structure:
characteristic:
1. This method is commonly used to Flutter
integrate the project into the native project for hybrid development. The native project is the main body (host)
2. Only native languages can be used in the project Flutter/Dart
. Native languages cannot be used directly, but packages containing native languages can be used.
3. Can be pubspec.yaml
used package/plugin
Applicable scene:
1. There are existing Native
projects, and the newly developed functions are Flutter
developed using them to improve efficiency.
2. There are already existing Flutter
projects, and module
the newly developed functions are integrated in this way.
Integration method:
1. Use the source code directly and integrate it into the native project
2. Package it into a resource package and integrate it into the project. For example, Android is packaged and aar
integrated into the project
There is a problem:
1. module
When integrating multiple, you need to consider Flutter Engine
the use. There will often Flutter Engine
be a problem that memory cannot be shared between them. After Dart 2.15, memory can be shared Isolate
within a group .isolate
2. Multiple ones Flutter engine
will consume a lot of resources.
3. When Native
opening the page , it takes a certain amount of time to initialize, causing a delay in page jump ("stuck").Flutter
Flutter Engine
5.2 Skeleton
Flutter 2.5
This method of creating projects will be supported from version 1 onwards. The essence is still the same Flutter Application
. This method is to provide a better project template for development and is no longer the default Couter App
. In the template, you can see assets
multiple best practices such as routing, resources, multi-language, status management, function-first folder organization, themes, etc.
5.3 FFI Plugin
FFI Plugin
It is an official way to integrate the local C source code function of the specified platform. Although the conventional one plugin
can also be supported, the main purpose is to support it method channel
, that is, dart
to call various related platforms API
( Android
or Java
, or , operating system ) Kotlin API
. ) , and the official meaning is that the support for C source code functions will be more powerful after 3.0, so if we only call C code and do not need a platform , we can consider using it .iOS
Objective-C
Swift API
Windows
C++ API
FFI Plugin
SDK API
FFI Plugin
After creating the project, let's observe FFI Plugin
the directory structure of the project. Compared with the conventional one plugin
, there are the following main differences:
The local source code files and CMakeLists.txt
files are now placed in the project src
directory. The source files under ios
the platform directory exist, but the source code under Classes
the project is introduced . The path in the properties of the platform file also points to .src
android
build.gradle
externalNativeBuild
cmake
src
CMakeLists.txt
pubspec.yaml
The following configuration options are provided in the project :
It means using ffiPlugin
it to compile source code for different platforms, and binding binary files to integrate into flutter
the application. Which platforms you need need to be reflected in this configuration item.
Finally, use DynamicLibrary
the method to load the library. For details, refer to the file lib
with the same name in the project directory dart
.
6. Summary
The above introduces flutter
the methods, differences and usage scenarios of creating different types of projects, and introduces in detail how to develop one Package
and Plugin
corresponding Package
project source code and upload GitHub
. If you are interested, you can refer to:
- flutter_package_demo:GitHub - ericwangjp/flutter_package_demo: A new flutter package demo project.
- flutter_plugin_demo:https://github.com/ericwangjp/flutter_plugin_demo