Flutter
三方的工具有两种,一种是包(Package
),一种是插件(Plugin
)。这两种差别在于 Plugin
不只包括了 Dart
代码,还包括了 iOS
以及 Android
的原生代码,比如常用的 image_picker
。而 Package
仅仅是包括 Dart
代码的库。
Package 开发
- 经过指令创立
Package
包
要创立 Dart
包,运用参数 --template=package
来履行 flutter create
。
flutter create --template=package 'package_name"
- 经过
Android Studio
创立Package
包
经过 Android Studio
创立 Package
的时分 Project type
选择 Package
类型。
这儿咱们经过对微信 Demo
中的索引控件代码进行抽取,创立一个自己的 Package
并在项目中进行运用。
代码抽取
library chenxi_chat_index_bar;
import 'package:flutter/material.dart';
class IndexBar extends StatefulWidget {
final void Function(String str)? indexBarCallBack;
const IndexBar({this.indexBarCallBack, Key? key}) : super(key : key);
@override
_IndexBarState createState() => _IndexBarState();
}
//获取选中的 item 文字
int _getIndex(BuildContext context, Offset globalPosition) {
//拿到点击小部件的盒子,也便是索引条
RenderBox box = context.findRenderObject() as RenderBox;
// 拿到 y 值, globalToLocal 当时位置间隔索引条左上角 (0, 0) 位置的间隔 (x, y)
double y = box.globalToLocal(globalPosition).dy;
//算出字符的高度
var itemHeight = screenHight(context) / 2 / INDEX_WORDS.length;
//算出第几个 item
int index = (y ~/ itemHeight).clamp(0, INDEX_WORDS.length - 1);
return index;
}
class _IndexBarState extends State<IndexBar> {
Color _bkColor = Color.fromRGBO(1, 1, 1, 0.0);
Color _textColor = Colors.black;
double _indicatorY = 0.0;
String _indicatorText = 'A';
bool _indicatorHidden = true;
@override
Widget build(BuildContext context) {
final List<Widget> _words = [];
for (int i = 0; i < INDEX_WORDS.length; i++) {
_words.add(
Expanded(child: Text(INDEX_WORDS[i],
style: TextStyle(fontSize: 10, color: _textColor),))
);
}
return Positioned(
right: 0.0,
top: screenHight(context) / 8,
height: screenHight(context) / 2,
width:120,
child: Row(
children: [
Container(
alignment: Alignment(0, _indicatorY),
width: 100,
child: _indicatorHidden ? null : Stack(
alignment: Alignment(-0.2, 0),
children: [
Image(image: AssetImage('images/气泡.png'), width: 60,),
Text(
_indicatorText,
style: TextStyle(
fontSize: 35, color: Colors.white,
),
)
],
),
), //指示器
GestureDetector(
onVerticalDragUpdate: (DragUpdateDetails details){
final Function(String str) callBack = widget.indexBarCallBack as Function(String str);
int index = _getIndex(context, details.globalPosition);
callBack(INDEX_WORDS[index]);
setState(() {
_indicatorY = 2.2 / INDEX_WORDS.length * index - 1.1;
_indicatorText = INDEX_WORDS[index];
_indicatorHidden = false;
});
},
// 索引条点击
onVerticalDragDown: (DragDownDetails details){
final Function(String str) callBack = widget.indexBarCallBack as Function(String str);
int index = _getIndex(context, details.globalPosition);
callBack(INDEX_WORDS[index]);
setState(() {
_bkColor = Color.fromRGBO(1, 1, 1, 0.4);
_textColor = Colors.white;
_indicatorY = 2.2 / INDEX_WORDS.length * index - 1.1;
_indicatorText = INDEX_WORDS[index];
_indicatorHidden = false;
});
},
// 索引条点击撤销
onVerticalDragEnd: (DragEndDetails details){
setState(() {
_bkColor = Color.fromRGBO(1, 1, 1, 0.0);
_textColor = Colors.black;
_indicatorHidden = true;
});
},
child: Container(
width: 20,
color: _bkColor,
child: Column(
children: _words,
),
),
), //索引条
],
),
);
}
}
//主题色
const Color CahtThemColor = Color.fromRGBO(230, 230, 230, 1.0);
//屏幕宽高
double screenWidth(BuildContext context) => MediaQuery.of(context).size.width;
double screenHight(BuildContext context) => MediaQuery.of(context).size.height;
const INDEX_WORDS = [
'',
'☆',
'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
'K',
'L',
'M',
'N',
'O',
'P',
'Q',
'R',
'S',
'T',
'U',
'V',
'W',
'X',
'Y',
'Z'
];
首先咱们把一切索引控件相关的代码都抽取到了 chenxi_chat_index_bar.dart
文件中。
Package 中资源文件处理
首先是不建议在 Package
中运用资源文件,因为会给别人的运用造成不方便。可是如果是 UI
界面相关的资源这个运用是咱们避免不了的,可是也是能够处理。
首先咱们创立一个 images
文件夹,并把图片资源放入进来。
在 pubspec.yaml
中进行相关装备。
发布相关装备
同样是在 pubspec.yaml
中进行发布相关的装备。
-
name
:Package
称号 -
description
:Package
的描述 -
version
:Package
的版本号 -
homepage
:能够放一个自己相关的网址链接,需求留意的是网址能够拜访,不然会被扣分。
发布 Package
- 查看
Package
flutter packages pub publish --dry-run
cd
到要发布的 Package
文件目录下,如果没有报错就代表没有缺失的信息,能够进行下一步。
- 发布
flutter packages pub publish
留意:现在发布插件跟包都需求
Do you want to publish chenxi_chat_index_bar 0.0.1 (y/N)? y
Pub needs your authorization to upload packages on your behalf.
In a web browser, go to https://accounts.google.com/o/oauth2/auth?access_type=offline&approval_prompt=force&response_type=code&client_id=818368855108-8grd2eg9tj9f38os6f1urbcvsq399u8n.apps.googleusercontent.com&redirect_uri=http%3A%2F%2Flocalhost%3A56076&code_challenge=jjz5gCzNNt_s5GYyQ3L_Pz4u_mSErJgx9BXoxUlY2XY&code_challenge_method=S256&scope=openid+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email
Then click "Allow access".
有时就算是翻墙也并不能处理问题,因为咱们还装备了相关镜像,Flutter
官方就建议经过镜像的装备,所以在发布插件或许包的时分,就会因为镜像呈现以下过错。
那么处理问题也很简单,便是指定服务器发布。
- 指定服务器发布
flutter packages pub publish --server=https://pub.dartlang.org
- LICENSE 证书问题
紧接着咱们应该会遇到这个过错,便是版权的问题,之前是不需求的,可是现在要求有必要要有。能够按下面过程处理。
在 github
上创立库房,勾选 Choose a license
,选择 BSD 3-Clause
,点击 Create repository
创立。
创立完结之后能够看到库房就有了 LICENSE
文件。
打开 LICENSE
文件,仿制一切内容。
把仿制的内容粘贴到 Package
中的 LICENSE
文件中,再次履行发布指令。
这儿能够看到已经发布成功了。
在 pub
官网,咱们也能够看到自己发布的 Package
了。
运用自己的 Package
履行 Pub get
能够看到咱们上传的 Package
包已经拉取到了本地。
运用时分引进以下头文件:
import 'package:chenxi_chat_index_bar/chenxi_chat_index_bar.dart' as chenxi;
加 as chenxi
是为了避免类名抵触。
运用代码:
chenxi.IndexBar(indexBarCallBack: (String str) {
if(_groupOffsetMap[str] != null) {
print(str);
_scrollController!.animateTo(_groupOffsetMap[str], duration: Duration(microseconds: 100), curve: Curves.elasticIn);
}
}),//悬浮的索引条
Package 优化
资源文件处理
因为 Package
包上传的是 lib
文件,所以在 Package
中需求用到例如图片资源的话,需求把图片资源添加到 lib
途径下。
AssetImage('images/bubble.png', package: 'chenxi_chat_index_bar')
运用图片的时分能够指定包名。这儿修改完之后需求对 Package
进行更新,需求修改 pubspec.yaml
跟 CHANGELOG.md
文件中的版本号重新发布。
assets:
- images/
- packages/chenxi_chat_index_bar/images/bubble.png
这样的话在项目中引进 Package
的时分,图片资源装备需求如上所示,会比较麻烦。对于这种情况,能够让外部运用的时分传图片进来。
class IndexBar extends StatefulWidget {
final void Function(String str)? indexBarCallBack;
final ImageProvider image;
const IndexBar(this.image, {this.indexBarCallBack, Key? key}) : super(key : key);
@override
_IndexBarState createState() => _IndexBarState();
}
展示的时分就直接用外部传入的 image
就好。
Image(image: widget.image, width: 60,),
分数优化
上传 Package
之后,官网会对咱们的包进行评分,如果评分太低的话别人运用的时分就会有顾忌。这儿总分是 130
分,咱们现在得到的是 90
分,然后能够依据官网的提示进行优化。
The package description is too short
阐明描述太短,这个咱们增加下描述就能够了。
-
No example found
没有示例工程
跟 github
上相同,当咱们运用一些比较老练的第三方的时分,都会有示例工程供咱们参考。这儿咱们也创立一个示例工程。
新建一个 flutter
工程,并引进 chenxi_chat_index_bar
指定本地 path
,然后添加示例代码。完结之后咱们要上传示例程序。
在咱们要发布的包 chenxi_chat_index_bar
中新建一个 example
文件,并把实例代码文件放到 example
文件下。
当咱们发布的包中代码比较多的话能够对代码进行拆分,创立多个子文件。并经过代码建立依靠关系。
- 指定子文件属于哪个主文件
part of 'chenxi_chat_index_bar.dart';
- 指定主文件包括哪些子文件
part 'index_bar.dart';
做完以上操作之后就能够再更新版本号进行重新上传。
Package
链接:chenxi_chat_index_bar
Plugin 开发
Plugin 指令创立
- 创立插件
要创立插件包请运用
--template=plugin
参数履行flutter create
。
flutter create --template=plugin 'plugin_name'
- 指定安排称号
运用 --org
选项指定你的安排,并运用反向域名表明法。
Dart
包package
是不需求安排称号的,--org
只有在--template=plugin
时才生效。
flutter create --org com.example --template=plugin 'plugin_name
- 指定其他言语
由于
Plugin
包括iOS
和Android
代码, 而他们别离都支撑两种言语,iOS
支撑Object-C(默许)
和Swift
,Android
支撑Java(默许)
和Kot in
, 所以咱们能够运用-i
或-a
为iOS
或Android
指定言语。
flutter create--template=plugin-i swift-ako tL in'plugin_name
Android Studio 创立 Plugin
创立工程的时分咱们选择 plugin
,这儿需求留意的是开发言语要选择自己了解的。
创立完结之后能够看到相对于 Package
这儿多了示例工程文件,而且包括 android
与 ios
文件夹。咱们示例工程要完成的功用是获取手机的电池电量,这儿只完成 ios
的相关代码。
代码完成
-
dart
代码
static Future<String> get platformBatteryLevel async {
final int batteryLevel = await _channel.invokeMethod('getBatteryLevel');
return batteryLevel.toString();
}
-
oc
代码
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
FlutterMethodChannel* channel = [FlutterMethodChannel
methodChannelWithName:@"chenxi_battery_level"
binaryMessenger:[registrar messenger]];
ChenxiBatteryLevelPlugin* instance = [[ChenxiBatteryLevelPlugin alloc] init];
[registrar addMethodCallDelegate:instance channel:channel];
}
- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
if ([@"getPlatformVersion" isEqualToString:call.method]) {
result([@"iOS " stringByAppendingString:[[UIDevice currentDevice] systemVersion]]);
} else if ([@"getPlatformBatteryLevel" isEqualToString:call.method]) {
result(@([self getBatteryLevel]));
} else {
result(FlutterMethodNotImplemented);
}
}
- (int)getBatteryLevel {
UIDevice *device = UIDevice.currentDevice;
device.batteryMonitoringEnabled = YES;
if (device.batteryLevel == UIDeviceOrientationUnknown) {
return -1;
}
return (int)(device.batteryState * 100);
}
发布 Plugin
- 查看
Plugin
flutter packages pub publish --dry-run
- 指定服务器发布
flutter packages pub publish --server=https://pub.dartlang.org
Plugin
的发布跟 Package
相同,cd
到 Plugin
文件目录下履行发布指令。
Plugin
链接:chenxi_battery_level