Package and Plugin developed by Flutter

Preface

There are two concepts of package and plug-in in flutter. Plug-in is packagea kind of . Its full name is plugin package, we call it abbreviated as pluginplug-in in Chinese. Package ( Package) mainly refers to flutterthe encapsulation of related functions, similar to Androidthe plug-ins in and iOSthe 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. PackageGenerally, it only contains Dartcode, while the plug-in not only contains Dart, but also contains native languages, such as Javaor in Android Kotlin, or iOSin Objective-Cand Swift. PackageHedu Pluginis 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 one pubspec.yamlfile and usually a libdirectory. pubspec.yamlThe file is a metadata file used to define the package name, version number, author and other information; libthe directory contains shared code, which contains at least one <package-name>.dartfile. One packagecan contain dependencies ( pubspec.yamldeclared 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 hellocreate a packageproject 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 Studiothe 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, iOSand 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 libcan be placed in the directory, and the test code can be written in testthe directory flutter_package_demo_test.dart .

Because  Package it is a simple  Dart library and does not have  Android 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.pathPackage

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 testthe 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 dialoghere as  an example. The project structure is as follows:Android iOS demo 

Create and write function verification code in  example the project libdirectory  :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, iOSnative 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 typeas shown below.

The first few steps  Package are the same as creation, the only difference is the third step, here  Project typeselectPlugin

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  pluginfunctional 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.iOSandroid 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 occalled through the class  swift.

FlutterPluginDemoPlugin.m You can see that the call is made in the class SwiftFlutterPluginDemoPlugin.swiftand 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:

Android screenshotiOS screenshots

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, versionneed 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://xxxxx

version: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 Frameworkcontain 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  plugincan also be supported, the main purpose is to support it  method channel, that is,  dart to call various related platforms API( Androidor 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  .iOSObjective-C Swift APIWindowsC++ APIFFI 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  flutterthe 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  Plugincorresponding  Package project source code and upload  GitHub. If you are interested, you can refer to:

Guess you like

Origin blog.csdn.net/you__are_my_sunshine/article/details/133354270