制造业外贸营销网站建设,商务网站建设规划流程,免费app模板下载网站,盘锦网站建设咨询前言 在flutter中有包和插件两个概念#xff0c;插件 (plugin) 是 package 的一种#xff0c;全称是 plugin package#xff0c;我们简称为 plugin#xff0c;中文叫插件。包(Package)主要指对flutter相关功能的封装#xff0c;类似于Android中的插件和iOS中的三方库。而插…前言 在flutter中有包和插件两个概念插件 (plugin) 是 package 的一种全称是 plugin package我们简称为 plugin中文叫插件。包(Package)主要指对flutter相关功能的封装类似于Android中的插件和iOS中的三方库。而插件(Plugin)主要指通过插件调用原生的功能如获取手机基本信息、获取原生的相机等。两者还是存在一定的差别的Package一般只包含Dart代码而插件除了包含有Dart外还会包含有原生的语言比如安卓中的Java或Kotlin和iOS中的Objective-C或Swift。Package和Plugin都是为了封装一些基础组件、业务组件等实现组件化开发这样项目中多处用到可以快速引入实现功能。 PackagesDart package最低要求是包含一个pubspec.yaml文件通常还包含一个lib目录。pubspec.yaml文件用于定义 package 名称、版本号、作者等其他信息的元数据文件lib目录包含共享代码其中至少包含一个package-name.dart文件。一个package可以包含依赖关系 (在pubspec.yaml文件里声明)、 Dart 库、应用、资源、字体、测试、图片和例子等。 pub.dev 上列出了很多 package由 Google 工程师和 Flutter 和 Dart 社区的开发者开发和发布你可以用在自己的应用里。Plugins 插件 (plugin package) 是一种特别的 package特别指那些帮助你获得原生平台特性的 package。插件可以为 Android (使用 Kotlin 或 Java 语言)、 iOS (使用 Swift 或 Objective-C 语言)、Web、macOS、Windows、Linux 平台或其任意组合的平台编写。比如某个插件可以为 Flutter 应用提供使用原生平台的摄像头的功能。 下面一起来看下如何开发 Package 与 Plugin 一、 包(Package)
1.1 创建 Package
使用命令行创建
flutter create --templatepackage hello
这将在 hello 目录下创建一个 package 项目并且包含以下内容 LICENSE 文件 大概率会是空的一个许可证文件。 test/hello_test.dart 文件 Package 的 单元测试 文件。 hello.iml 文件 由 IntelliJ 生成的配置文件。 .gitignore 文件 告诉 Git 系统应该隐藏哪些文件或文件夹的一个隐藏文件。 .metadata 文件 IDE 用来记录某个 Flutter 项目属性的的隐藏文件。 pubspec.yaml 文件 pub 工具需要使用的包含 package 依赖的 yaml 格式的文件。 README.md 文件 起步文档用于描述 package。 lib/hello.dart 文件 package 的 Dart 实现代码。 .idea/modules.xml、.idea/workspace.xml 文件 IntelliJ 的各自配置文件包含在 .idea 隐藏文件夹下。 CHANGELOG.md 文件 又一个大概率为空的文档用于记录 package 的版本变更。 推荐使用 Android Studio 进行创建打开 Android Studio选择 New Flutter Project首先需要选择该 package 使用的 flutter sdk 然后需要输入插件名、文件目录、插件类型可以选择是 Package 还是 Plugin支持开发平台及对应的开发语言 这里输入项目名字为 flutter_package_demo然后 Project type 选择 Package,平台暂时只选择 Android、iOS开发语言选择对应的 kotlin、Swift 然后创建项目后目录结构如下 Package 项目的目录结构较为简单主要是 lib 目录下的和项目同名的类flutter_package_demo.dart该类主要是用于在里面暴露出包中的类以便其它项目调用。Package 中的代码实现放在lib目录下即可测试代码写在test目录下的flutter_package_demo_test.dart 中即可。
因为 Package 是个单纯的 Dart 库没有 Android 和 iOS 壳工程所以不能直接运行该Package 进行联调测试可以在自己的项目中通过本地依赖path引入该 Package然后可以通过在项目中调用进行测试联调。
1.2 定义 Package
这里创建好项目后模版代码在 flutter_package_demo.dart 中已经生成了一个方法
library flutter_package_demo;/// A Calculator.
class Calculator {/// Returns [value] plus 1.int addOne(int value) value 1;
}
这里的 library flutter_package_demo 表明该 package 是一个可依赖包包的名字为flutter_package_demo 1.3 验证 Package
由于这里不涉及页面 UI该逻辑可以直接在单元测试中进行验证代码写在test目录下的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);});
}
然后启动单元测试 如果是涉及 UI 的 package本地测试时可以直接在当前项目下创建 example 目录在里面开发功能验证代码或者在外部使用的项目中通过如下方式在 pubspec.yaml 中引入包
flutter_package_demo:path: ../ # package 所在的路径绝对或者相对
1.4 包含 UI 的 Package
下面改造一下项目让 package 提供一个对外可显示的 material dialog先来定义package:
library flutter_package_demo;export caculator.dart;
export dialogs.dart;
包名不变把逻辑代码移除导出了两个文件第一个为上述的加1方法的抽离第二个为我们要显示的 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 Futurevoid materialDialog({required BuildContext context,Function(dynamic value)? onClose,String? title,String? msg,ListWidget? 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,ListWidget? 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));}
}接着增加 example 工程来验证我们的 dialog这里为了简单以 Android 为例就不添加iOS demo 工程了项目结构如下: 在 example 工程的lib目录下创建 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);overrideWidget 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);overrideStateHomePage createState() _HomePageState();
}class _HomePageState extends StateHomePage {int value 0;overrideWidget 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),);}
}页面效果如下 二、 插件(Plugin)
Plugin 和 Package 最大的差别在于 Plugin 可以跨平台访问原生API提供的能力然后通过插件调用原生 Android 和 iOS 的功能以实现某些功能或者更好的用户体验如获取手机版本信息、调用原生摄像头等代码包含有 Dart、Android 原生代码、iOS原生代码。 2.1 创建Plugin
和创建Package类似同样可以使用命令行进行创建
flutter create --org com.example --templateplugin --platformsandroid,ios -a kotlin helloflutter create --org com.example --templateplugin --platformsandroid,ios -a java helloflutter create --org com.example --templateplugin --platformsandroid,ios -i objc helloflutter create --org com.example --templateplugin --platformsandroid,ios -i swift hello4 条指令可以根据选择的插件平台和开发语言自由选择其中之一这将在 hello 目录下创建一个插件项目其中包含以下内容 lib/hello.dart 文件 Dart 插件 API 实现。 android/src/main/java/com/example/hello/HelloPlugin.kt 文件 Android 平台原生插件 API 实现使用 Kotlin 编程语言。 ios/Classes/HelloPlugin.m 文件 iOS 平台原生插件 API 实现使用 Objective-C 编程语言。 example/ 文件 一个依赖于该插件并说明了如何使用它的 Flutter 应用。 默认情况下插件项目中 iOS 代码使用 Swift 编写 Android 代码使用 Kotlin 编写 要在现有的插件项目中添加对特定平台的支持请在项目目录运行 flutter create 命令并加入--templateplugin。例如要对现有的插件项目添加 Web 支持请运行以下命令
flutter create --templateplugin --platformsweb .
建议使用IDE进行创建比较直观且易操作。
1、首先打开 Android Studio然后点击 File-New-New Flutter Project。
2、进入到选择 flutter sdk 页面选择自己本地的 flutter然后点击 next。
3、选择 Plugin type如下图所示。
前几个步骤和创建 Package 是一样的唯一的区别在与第三步这里 Project type选择Plugin 点击 create 后创建项目项目结构如下 lib 目录下的文件为插件的 flutter 具体实现example 是插件测试项目可以对 plugin进行功能测试iOS 目录下为插件的iOS端原生实现android 目录下为插件的 Android 端原生实现test 目录为插件对应的单元测试。 2.2 定义Plugin
这里先重点关注 lib 目录下的三个文件
接口定义
flutter_plugin_demo_platform_interface.dart定义接口的地方该文件只定义方法。getPlatformVersion()为创建项目时自动生成的方法这里我们新增一个getScreenWidth()方法来获取屏幕宽度:
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;}FutureString? getPlatformVersion() {throw UnimplementedError(platformVersion() has not been implemented.);}FutureString? getScreenWidth() {throw UnimplementedError(getScreenWidth() has not been implemented.);}
}接口实现
接口实现主要在 flutter_plugin_demo_method_channel 文件中该文件为上述 interface 的子类负责具体接口的实现但方法的具体实现依赖于调用原生端的实现。
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.visibleForTestingfinal methodChannel const MethodChannel(flutter_plugin_demo);overrideFutureString? getPlatformVersion() async {final version await methodChannel.invokeMethodString(getPlatformVersion);return version;}overrideFutureString? getScreenWidth() async {final screenWidth await methodChannel.invokeMethodString(getScreenWidth);return screenWidth;}
}这里 getScreenWidth 的实现需要通过 methodChannel 调用原生方法。
调用
和 plugin 项目同名的类 flutter_plugin_demo.dart 主要是供外部调用该类中提供了所有对外调用的方法。这个类提供的方法包含两类一类为使用 Dart 直接实现一类为需要依赖于原生端实现需要调用 flutter_plugin_demo_platform_interface 接口类中的方法
import flutter_plugin_demo_platform_interface.dart;class FlutterPluginDemo {FutureString? getPlatformVersion() {return FlutterPluginDemoPlatform.instance.getPlatformVersion();}FutureString? getScreenWidth() {return FlutterPluginDemoPlatform.instance.getScreenWidth();}// 直接 dart 实现int getScreenHeight() {return 1080;}
}
2.3 iOS 原生实现
iOS 目录主要为 iOS 原生端实现这里可以使用 example 下的 iOS 项目进行调试因项目默认没有 pod 文件所以需要对 example 目录下的 iOS 进行 pod install。
这里需要注意的是创建项目时选择的是 Swift 语言所以具体实现是在 swift 类中若选择的是oc则实现是在 oc 类中。其实 swift 的实现也是通过oc的类调用的 swift。
在 FlutterPluginDemoPlugin.m 类中可以看到调用的是SwiftFlutterPluginDemoPlugin.swift具体的实现是在该类中
#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
#endifimplementation FlutterPluginDemoPlugin(void)registerWithRegistrar:(NSObjectFlutterPluginRegistrar*)registrar {[SwiftFlutterPluginDemoPlugin registerWithRegistrar:registrar];
}
end
SwiftFlutterPluginDemoPlugin 类中实现
import Flutter
import UIKitpublic 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.boundslet screenWidth screenRect.size.widthlet screenHeight screenRect.size.heightresult(iOS \(screenWidth))case getPlatformVersion:result(iOS UIDevice.current.systemVersion)default:result(no such method !)}}
}
2.4 Android 原生实现
因为创建项目时选择的语言为 kotlin因此 Android 的原生实现在 kotlin 目录下与项目同名的 FlutterPluginDemoPlugin.kt 文件中
package com.example.flutter_plugin_demoimport android.content.Context
import androidx.annotation.NonNullimport 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 Activityprivate lateinit var channel : MethodChannelprivate var context: Context? nulloverride fun onAttachedToEngine(NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {channel MethodChannel(flutterPluginBinding.binaryMessenger, flutter_plugin_demo)context flutterPluginBinding.applicationContextchannel.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 功能验证
完成以上步骤我们的插件就开发完成了接下来让我们在 example 项目中验证下我们刚刚开发的插件在 example/lib/main.dart 中编写测试代码
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});overrideStateMyApp createState() _MyAppState();
}class _MyAppState extends StateMyApp {String _platformVersion Unknown;String _screenWidth Unknown;final _flutterPluginDemoPlugin FlutterPluginDemo();overridevoid initState() {super.initState();initPlatformState();_getScreenWidth();}// Platform messages are asynchronous, so we initialize in an async method.Futurevoid 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;});}Futurevoid _getScreenWidth() async {String screenWidth;try {screenWidth await _flutterPluginDemoPlugin.getScreenWidth() ?? 0;} on PlatformException {screenWidth Failed to get screen width.;}if (!mounted) return;setState(() {_screenWidth screenWidth;});}overrideWidget 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),),],),),);}
}
最终页面效果 三、发布
发布主要有两种一种是发布到 Flutter 的官方一种是发布到自己公司的私有库中两者发布步骤大部分都是相同的在一些地方存在差异下面对这两种发布方法进行介绍。 3.1 发布前准备
首先需要检查下 Package 或 Plugin 中是否包含有 pubspec.yaml、README.md、CHANGELOG.md、LICENSE 这四个文件需要检查下完整性。这四项内容默认创建的时候都会有若缺少可以在项目终端中运行 flutter create .进行补全注意有个点。 pubspec.yaml
该文件主要是引用外部插件其中 name、description、version、homepage 需要填写完整publish_to 指将该库发布到指定位置发布到私有库需要若发布到 pub.dev 则不需要。 README.md
该文件主要是写插件或包的内容便于别人查看时告知该库的作用。 CHANGELOG.md
该文件主要是记录插件或包的版本修改记录说明每个版本的更新内容。 LICENSE
该文件主要是添加许可证书可根据需要填写 上述准备工作完成后需要对项目进行校验打开终端进入插件或包的路径然后运行
flutter packages pub publish --dry-run
然后查看运行结果如果警告信息为0说明没什么问题就可以进行发布了。 3.2 发布
校验完成以后就可以发布了还是使用命令行最好先科学上网然后再运行命令进行发布
flutter packages pub publish
发布到官方和私有库有点区别若发布到官方运行命令后会多一步登录谷歌账号校验的步骤而发布到私有库不需要。
发布到私有库需要进行私有仓库的搭建这个网上有很多教程可以参考下Flutter私有仓库搭建
注意
设置了中国镜像的开发者目前所存在的镜像都不能也不应该进行 package 的上传。如果你设置了镜像执行上述发布代码可能会造成发布失败。网络设定好后无需取消中文镜像执行下述代码可直接上传
flutter pub publish --serverhttps://pub.dartlang.org 四、使用
4.1 依赖 pub.dev 仓库的 package 包 cupertino_icons: ^1.0.2 4.2 依赖远程 git 仓库的 package 包 flutter_plugin_name: git: url: https://github.com/xxxxxx/xxxxxx.git #git仓库地址 path: xxxxx #如果项目不是在git地址的根目录 则需要指定path ref: ‘1.0.0 #指定的版本 对应git仓库中的tag标签 也可以指定分支 ref: some-branch 4.3 依赖私有 pub 仓库的 package 包 flutter_plugin_name: hosted: name: flutter_plugin_name url: https://xxxxx version:1.0.3 4.3 依赖本地仓库的 package 包 flutter_plugin_name: path: ../ #可以是相对路径也可以是绝对路径 五、其他
在创建项目的时候我们发现还有其他几个类型的 Project type 可选Application 大家都很熟悉了它是一个纯 flutter 项目主体是 Flutter当然它也可以接入 Android Module 或者 iOS Framework其内部包含 Android 和 iOS 项目。Plugin、Package 上面已经介绍过了下面来简单看下剩余的几个类型 5.1 Module
项目结构 特性
1、这种方式常用与将 Flutter 项目集成到原生项目中进行混合开发原生项目是主体宿主
2、项目中只能使用 Flutter/Dart不能直接使用原生语言但是可以使用包含原生语言的 package
3、可以在 pubspec.yaml 使用 package/plugin 适用场景
1、已有 Native 项目新开发的功能使用 Flutter 开发提高效率 2、已存在旧的 Flutter 项目以 module 方式集成新开发的功能 集成方式
1、直接使用源码集成到原生项目中
2、打包成资源包集成到项目中。如安卓打包成 aar 集成到项目中 存在问题
1、集成多个 module 时需要考虑 Flutter Engine 的使用。多 Flutter Engine 会存在内存之间不能共享的问题。Dart 2.15 之后Isolate 组之内的 isolate 可以共享内存。
2、多个 Flutter engine 会消耗大量资源
3、Native 打开 Flutter 页面时由于 Flutter Engine 需要初始化需要消耗一定时间造成页面跳转存在延迟“卡顿” 5.2 Skeleton 这种创建项目方式从 Flutter 2.5 版本以后开始支持本质还是一个 Flutter Application这种方式就是为开发提供一种较好的项目模板不在是默认的 Couter App。在模板中可以看到路由、assets 资源、多语言、状态管理功能优先」的文件夹组织方式、主题等多种最佳实践方式 5.3 FFI Plugin
FFI Plugin 是官方提供的一种方式来集成指定平台的本地C源代码功能虽然常规的 plugin也可以支持但是主要用途还是支持 method channel即 dart 调用各种相关平台的 APIAndroid 中的 Java 或 Kotlin APIiOS 中的 Objective-C 或 Swift APIWindows操作系统中的C API而且官方的意思是3.0之后对C源代码功能的支持 FFI Plugin 会更强大所以我们如果只是调用C代码不需要平台 SDK API 的话可以考虑使用 FFI Plugin。 创建完项目后我们观察一下 FFI Plugin 项目的目录结构对比常规 plugin主要有以下几点不同
本地的源代码文件和 CMakeLists.txt 文件现在统一放到项目的 src 目录下ios 平台目录Classes 下面的源文件存在只是引入了项目 src 下面的源代码android 平台 build.gradle 文件中 externalNativeBuild 属性中 cmake 的路径也是指向 src 中的CMakeLists.txt。 项目中的 pubspec.yaml 提供了如下配置选项
代表利用 ffiPlugin 去为各个不同的平台编译源代码并且绑定了二进制文件集成到 flutter应用中去你需要哪些平台都需要体现在这个配置项中。 最后通过 DynamicLibrary 来加载库中的方法具体参考项目 lib 目录下的同名 dart 文件。 六、总结
以上介绍了创建 flutter 不同类型项目的方式、差别与使用场景并详细介绍了如何开发一个Package 与 Plugin对应 Package 项目源码与上传 GitHub感兴趣可参考 flutter_package_demoGitHub - ericwangjp/flutter_package_demo: A new flutter package demo project.flutter_plugin_demohttps://github.com/ericwangjp/flutter_plugin_demo