Flutter学习指南:封装 API 插件

栏目: IOS · Android · 发布时间: 5年前

内容简介:Flutter学习指南6.文件存储和网络5.交互、手势和动画

Flutter学习指南

6.文件存储和网络

5.交互、手势和动画

4.UI布局和控件

3.熟悉Dart语言

2.编写第一个应用

1.开发环境搭建

本文是学习指南系列的第7篇文章,建议大家收藏起来,欢迎分享给他人。

本篇文章我们先一起学习 Flutter 插件的使用,然后通过开发一个 toast 插件来学习它的开发,最后发布到 Pub 上。

插件的使用

Flutter 的库是以 package 的方式来管理。Package 分为两种,Dart package(也叫 library package) 和 plugin package。当我们说 Fluter 包的时候,指的其实也是 Dart 包,它只能使用 Dart 和 Flutter 提供的 API;而当我们说 Flutter 插件时指的是后者,也就是 plugin package。Flutter 插件通常会包含平台特定的代码。对包的使用者来说,两者没有区别。

添加依赖

为了使用一个库,我们首先在 pubspec.yaml 里声明一个依赖:

dependencies:
  shared_preferences: ^0.4.2
复制代码

^0.4.2 表示与 0.4.2 兼容的版本。我们也可以指定依赖库的为特定的版本:

  • any:任意版本
  • 1.2.3:特定的版本
  • <1.2.3:小于 1.2.3 的版本,此外还有 <=、>、>= 可以使用
  • '>=1.2.3 <2.0.0':指定一个范围

接下来,在项目的根目录执行 flutter packages get。如果你使用 Android Studio 进行开发,也可以直接在 pubspec.yaml 的编辑页面上面点击 Packages get 按钮。

上面例子的是发布在 pub.dartlang.org 上的库,除此之外,我们也可以使用其他的源:

dependencies:
  transmogrify:
    hosted:
      name: transmogrify
      url: http://your-package-server.com
    version: ^1.4.0

  kittens:
    git:
      url: git://github.com/munificent/cats.git
      ref: some-branch  # 可选的

  kittens:
    git:
      url: git://github.com/munificent/cats.git
      path: path/to/kittens  # 指定路径

    # 甚至可以指定一个本地路径
    transmogrify:
      path: /Users/me/transmogrify
复制代码

如果你看过 Flutter 的 pubspec,应该会注意到 flutter 是这样声明的:

dependencies:
  flutter:
    sdk: flutter
复制代码

sdk 用于导入随 Flutter 一起发布的包,目前只有 flutter。

使用

导入相关的包后,我们就可以使用它的 API 了:

import 'package:shared_preferences/shared_preferences.dart';

void foo() async {
  var prefs = await SharedPreferences.getInstance();
  var used = prefs.getBool('used');
  if (!used) {
    prefs.setBool('used', true);
  }
}
复制代码

这种导入方式的问题在于,他把库里所有的符号到导入到了全局的命名空间里面(比方说,在上面的例子里,我们可以直接使用 SharedPreferences)。有时为了防止命名空间的污染,我们可以使用 as 给导入的库一个名字(当然,对 SharedPreferences 其实没有必要使用限定名就是了):

void foo() async {
  var prefs = await sp.SharedPreferences.getInstance();
  var used = prefs.getBool('used');
  if (!used) {
    prefs.setBool('used', true);
  }
}
复制代码

了解了 Flutter 包的使用后,下面我们自己来开发一个 flutter 插件。

开发一个插件

学习 Flutter 的过程中,不知道是你是否注意到 Flutter 并没有提供一个 Toast API。为了弥补这个遗憾,在这一节里我们就来开发一个插件,让它支持 Toast。

在开始开发前,我们先来了解一下 Flutter 如何跟平台相关的代码进行通信。

MethodChannel

Flutter 跟平台相关代码可以通过 MethodChannel 进行通信。客户端通过 MethodChannel 将方法调用和参数发生给服务端,服务端也通过 MethodChannel 接收相关的数据。

Flutter学习指南:封装 API 插件
PlatformChannels

需要注意的是,上图中的箭头是双向的。也就是说,我们不仅可以从 Flutter 调用 Android/iOS 的代码,也可以从 Android/iOS 调用 Flutter。调用时相关的参数对应如下:

Dart Android iOS
null null nil (NSNull when nested)
bool java.lang.Boolean NSNumber numberWithBool:
int java.lang.Integer NSNumber numberWithInt:
int, if 32 bits not enough java.lang.Long NSNumber numberWithLong:
double java.lang.Double NSNumber numberWithDouble:
String java.lang.String NSString
Uint8List byte[] FlutterStandardTypedData typedDataWithBytes:
Int32List int[] FlutterStandardTypedData typedDataWithInt32:
Int64List long[] FlutterStandardTypedData typedDataWithInt64:
Float64List double[] FlutterStandardTypedData typedDataWithFloat64:
List java.util.ArrayList NSArray
Map java.util.HashMap NSDictionary

创建项目

这里假设读者使用 Android Studio 开发。

  1. 在菜单上选择 File -> New -> New Flutter Project
  2. 在弹出的面板里选择 Flutter Plugin,点击 next
  3. Project name 我们填入 flutter_toast2018,其他信息读者根据自身需要填写

之所以叫 flutter_toast2018 是因为 Pub 上已经有一个 flutter_toast,所以加上 2018 防止名字冲突。

生成的项目有 4 个主要的目录:

  • android:插件本地代码的 Android 端实现
  • ios:iOS 端的实现
  • lib:Dart 代码。插件的客户将会使用这里实现的接口
  • example:插件的使用示例

插件开发

Android 端代码实现

其实在上一步我们生成项目的时候,项目里就已经包含了一个实现了 platformVersion 的 Flutter 插件 demo,有兴趣的读者可以看看学习一下。下面,我们来开发自己的 Toast 插件(注意,我们的实现只支持 Android)。

首先我们来了解一下接口 MethodCallHandler:

public interface MethodCallHandler {
  void onMethodCall(MethodCall call, Result result);
}
复制代码

这个接口用于处理 Flutter 的本地方法调用请求。也就是说,我们需要实现这个接口,当 Flutter 调用我们的时候,弹出一个 toast。

实现这个接口的是 FlutterToast2018Plugin(位于 android 目录下):

public class FlutterToast2018Plugin implements MethodCallHandler {
  public static void registerWith(Registrar registrar) {
    // "example.com/flutter_toast2018" 是我们 method channel 的名字,Dart 代码里还需要用到它。
    // 为了防止命名冲突,可以在它的前面加上域名
    final channel = new MethodChannel(registrar.messenger(), "example.com/flutter_toast2018");
    channel.setMethodCallHandler(new FlutterToast2018Plugin());
  }

  @Override
  public void onMethodCall(MethodCall call, Result result) {
    // TODO
  }
}
复制代码

为了弹出 Toast,我们给 FlutterToast2018Plugin 的构造函数添加一个 Context 参数:

public class FlutterToast2018Plugin implements MethodCallHandler {
  private final Context mContext;

  public FlutterToast2018Plugin(Context context) {
    mContext = context;
  }

  // 注册 MethodCallHandler
  public static void registerWith(Registrar registrar) {
    final channel = new MethodChannel(registrar.messenger(), "example.com/flutter_toast2018");
    // context 可以从 Registrar 拿到
    channel.setMethodCallHandler(new FlutterToast2018Plugin(registrar.context());
  }

  // ...
}
复制代码

现在,实现 onMethodCall 方法:

public class FlutterToast2018Plugin implements MethodCallHandler {
  // ...

  @Override
  public void onMethodCall(MethodCall call, Result result) {
    // call.method 是方法名,这里我们就叫它 toast
    if (call.method.equals("toast")) {
      // 调用本地代码的时候,只能传递一个参数。为了传递多个,可以把参数放在一个 map 里面。
      // call.arguemnt() 方法支持 Map 和 JSONObject
      String content = call.argument("content");
      String duration = call.argument("duration");
      Toast.makeText(mContext, content,
                     "short".equals(duration) ? Toast.LENGTH_SHORT : Toast.LENGTH_LONG)
              .show();
      // 执行成功
      result.success(true);
    } else {
      result.notImplemented();
    }
  }
}
复制代码

Flutter 端

Flutter 端需要做的,就是生成一个 MethodChannel,然后通过这个 MethodChannel 调用 toast 方法:

import 'dart:async';
import 'package:flutter/services.dart';

enum ToastDuration {
  short, long
}

class FlutterToast {
  // 这里的名字要跟  Java  端的对应
  static const MethodChannel _channel =
      const MethodChannel('example.com/flutter_toast2018');

  static Future<bool> toast(String msg, ToastDuration duration) async {
    var argument = {
      'content': msg,
      'duration': duration.toString()
    };
    // 本地方法是一个异步调用。'toast' 对应我们在前面 Java 代码的 onMethodCall
    // 方法里面处理的方法名
    var success = await _channel.invokeMethod('toast', argument);
    return success;
  }
}
复制代码

使用插件

在这一节我们修改工程里 example 目录下的示例,用它来演示插件的使用:

import 'package:flutter/material.dart';

// 首先导入我们的包
import 'package:flutter_toast2018/flutter_toast2018.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new Scaffold(
        appBar: new AppBar(
          title: const Text('Plugin example app'),
        ),
        body: new Center(
          child: RaisedButton(
            child: Text('toast'),
            // 插件的使用跟其他库没有什么区别,直接调用即可
            onPressed: () => FlutterToast2018.toast(
              'Toast from Flutter', ToastDuration.short
            ),
          ),
        ),
      ),
    );
  }
}
复制代码

发布插件

前面我们说过,pubspec 支持通过本地路径和 Git 导入依赖,但为了更好的管理版本依赖,还是推荐发布插件到pub.dartlang.org/。在这一节,我们就把前面开发的 toast 插件发布到 Pub 上。

需要注意的是,由于某些众所周知的原因,pub.dartlang.org 需要一把梯子才能上去。虽然我们也可以通过 flutter-io.cn 来发布,但上传的时候需要登录 Google 账号,梯子还是少不了的。

检查配置

首先是 pubspec.yaml。对 Flutter 插件来说,pubspec 里除了插件的依赖,还包含一些元信息,读者可以根据需要,把这些补上:

name: flutter_toast2018
description: A new Flutter plugin for Android Toast.
version: 0.0.1
author: Jekton <ljtong64@gmail.com>
homepage: https://jekton.github.io/
复制代码

另外,发布到 Pub 上的包需要包含一个 LICENSE,关于 LICENSE 文件,最简单的方法就是在 GitHub 创建仓库的时候选中一个。

检查插件

现在,我们在工程的根目录执行以下命令,检测一下插件有没有什么问题:

flutter packages pub publish --dry-run
复制代码

如果一切正常,将会输出:

...

Package has 0 warnings.
复制代码

发布插件

发布插件和上一步一样,只是少了 --dry-run 参数:

flutter packages pub publish
复制代码

如果是第一次发布,会提示验证 Google 账号。授权后便可以继续上传,如果成功的话,会提示“Successful uploaded package”:

Looks great! Are you ready to upload your package (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=xxxxxxxxxxxxxx-8grd2eg9tj9f38os6f1urbcvsq399u8n.apps.googleusercontent.com&redirect_uri=http%3A%2F%2Flocalhost%3A52589&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email
Then click "Allow access".

Waiting for your authorization...
Successfully authorized.
Uploading...
Successful uploaded package.
复制代码

前面我们发布的包可以在 pub.dartlang.org/packages/fl…pub.flutter-io.cn/packages/fl… 找到。

相关的代码则是放到了 GitHub 上:

git clone https://github.com/Jekton/flutter_toast2018.git
复制代码

最后再提一提我们没有讲到的 Flutter package。为了开发一个 Flutter 包,我们在创建项目的时候可以选择 Flutter package。它和 Flutter 插件唯一的区别是Flutter package 不能包含平台特定的代码(只能使用 Dart 和 Flutter API)。除此之外,开发、发布和使用都跟 Flutter 插件没有什么区别。

编程·思维·职场

Flutter学习指南:封装 API 插件


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

永无止境

永无止境

[美] 道格拉斯•艾德华兹 / 刘纯毅 / 中信出版社 / 2012-12-15 / 59.00元

★ 值得中国初创公司反复思考的企业传记 ★ 互联网行业必读书 ★ Google高管揭开Google的神秘面纱 ★ 探寻“G力量”重塑人类知识景观的心路历程 ★ Google走过的路,Google未来的路 ★ 编辑推荐: 它是目前被公认为全球最大的搜索引擎!它是互联网上五大最受欢迎的网站之一! 它在操作界面中提供多达30余种语言选择,在全球范围内拥有无数用户......一起来看看 《永无止境》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

随机密码生成器
随机密码生成器

多种字符组合密码

SHA 加密
SHA 加密

SHA 加密工具