flutter image_Flutter插件的故事(第1部分):Flutter中对Core Image过滤器的支持

flutter image

As Flutter is still in development most native features aren't available for now. But Flutter isn’t so amazing if it’s not possible to create a plugin that can solve the developer’s needs.

由于Flutter仍在开发中,因此大多数本地功能暂时不可用。 但是,如果无法创建能够满足开发人员需求的插件,Flutter并不会那么令人惊讶。

I’ve decided to develop a plugin to make it possible to use native Core Image filters in Flutter on iOS, and GPUImage library on Android. Not to stuck into problems I suggest starting from iOS part and then add Android-related code. It will help us to concentrate only on single platform problems.

我决定开发一个插件,以便可以在iOS的Flutter和Android的GPUImage库中使用本机Core Image过滤器。 不要陷入问题,我建议从iOS部分开始,然后添加与Android相关的代码。 这将帮助我们仅专注于单个平台问题。

I expect, as a result, we will have not only a new package but someone will find enough information to create his own plugin to make Flutter grater.

我希望结果是,我们不仅会有一个新的软件包,而且有人会找到足够的信息来创建自己的插件以使Flutter更加轻巧。

To create a new plugin project you can use the command line or IDE menu. It doesn't matter what you choose, both instruments work perfectly and do the same. Let’s look at the command below to understand what options do you have. org is used for Android only, it’s obvious to have here libraries connected to some organization. a allows you to choose a language for Android plugin. It can be Java or Kotlin. i does the same for iOS. You can write code using Swift or Objective-C, and nowadays it’s better to use Swift.

要创建新的插件项目,可以使用命令行或IDE菜单。 不管您选择什么,这两种仪器都能完美地工作并且相同。 让我们看下面的命令,以了解您有哪些选项。 org仅用于Android,显然这里的库已连接到某个组织。 a允许您选择Android插件的语言。 它可以是Java或Kotlin。 i为iOS做同样的事情。 您可以使用Swift或Objective-C编写代码,如今最好使用Swift。

flutter create --org me.nativefilters --template=plugin -a java -i swift native_filters

So we’ve created a new project and opened it in your favorite IDE. You need to concentrate your sight on three folders: ios, android, lib. All plugin related code we will put here, and it’s obvious which code should be placed in which directory.

因此,我们创建了一个新项目,并在您喜欢的IDE中将其打开。 您需要将注意力集中在三个文件夹上: iosandroidlib 。 我们将在此处放置所有与插件相关的代码,很明显,应将哪个代码放置在哪个目录中。

Every plugin has a built-in example project that can be used to test changes. It’s possible to create your own example project or even attach the plugin to an existed project and develop it there. But it’s not a theme for the current discussion.

每个插件都有一个内置的示例项目,可用于测试更改。 可以创建自己的示例项目,甚至可以将插件附加到现有项目并在那里进行开发。 但这不是当前讨论的主题。

Flutter provides a single instrument to bind native code and dart code — MethodChannel. It allows us to invoke native code using a few methods from this class. The major difference between them all lies in returning type. If we need list or map data from native code, we need to use specific methods. In all other cases, invokeMethod will be enough.

Flutter提供了一种绑定本机代码和dart代码的MethodChannel 。 它允许我们使用此类中的一些方法来调用本机代码。 它们之间的主要区别在于返回类型。 如果我们需要从本机代码中列出或映射数据,则需要使用特定的方法。 在所有其他情况下, invokeMethod就足够了。

invokeMethod(name, arguments)
invokeListMethod(name, arguments)
invokeMapMethod(name, arguments)

All those methods use string as the first parameter. This argument is needed to differentiate a message sent to native code. If you are familiar with the message-driven architecture, some paradigms here won’t be new for you.

所有这些方法都使用string作为第一个参数。 需要此参数来区分发送到本机代码的消息。 如果您熟悉消息驱动的体系结构,那么这里的某些范例对您来说并不是新事物。

To create a native channel we need to name it. This name is used to bind a channel created in native code to another one created in dart code. We have here something close to socket communication. If you are a Java developer, you may look on it like ServerSocket and ClientSocket. But in this implementation, it’s not obvious which connection is server and which is the client, as there are no specific classes for it. We just create a channel on Swift/Java code and channel in Dart code, and that's all. Actually, a native channel is a server, and Dart is a client one.

要创建本机频道,我们需要为其命名。 此名称用于将以本机代码创建的通道绑定到以dart代码创建的另一个通道。 我们这里有一些接近套接字通信的内容。 如果您是Java开发人员,则可以像ServerSocketClientSocket一样看它。 但是在此实现中,不清楚哪个连接是服务器,哪个连接是客户端,因为没有特定的类。 我们仅在Swift / Java代码上创建一个通道,在Dart代码中创建一个通道,仅此而已。 实际上,本机通道是服务器,而Dart是客户端。

A plugin may have as many MethodChannel instances as we needed, so don’t think that you need only one instance.

一个插件可能有我们需要的许多MethodChannel实例,因此不要以为只需要一个实例。

In this article, I’m not going to create a fully-ready plugin. At first, I want to implement the possibility to create a filter instance and display some useful information about it and that's all for now. If you aren’t familiar with Core Image filters, read about it on the official documentation site.

在本文中,我不会创建一个完全可用的插件。 首先,我想实现创建过滤器实例并显示有关它的有用信息的可能性,仅此而已。 如果您不熟悉Core Image过滤器, 在官方文档站点上阅读有关它的信息。

To create a Core Image filter we need to know its name, so let's start our journey from finding all available filters’ names. I’m going to use a factory pattern to instantiate filter object in Dart. It’s the most suitable way of doing what we need. This factory will be responsible for creating and destroying new objects, and here I will create a method to obtain a list of available filters. So in lib folder, I’ve created a new file and define a new factory class inside.

要创建Core Image过滤器,我们需要知道其名称,因此让我们从查找所有可用过滤器的名称开始。 我将使用工厂模式在Dart中实例化过滤器对象。 这是做我们需要的最合适的方法。 该工厂将负责创建和销毁新对象,在这里,我将创建一种方法来获取可用过滤器的列表。 因此,在lib文件夹中,我创建了一个新文件,并在其中定义了一个新的工厂类。

For now, I want you to concentrate only on one thing — how to get a list of available filter names. As you can see I’ve created MethodChannel with the name CIFilterFactory and it means that in the future in swift code I have to create a channel with the same name to make it works. As I need a list of items I use invokeListMethod. It’s the generic method, so we need to specify generic type otherwise we obtain cast error as items will be of a dynamic type. Everything related to error handling I’ve left for the future.

现在,我只想让您专注于一件事-如何获取可用过滤器名称的列表。 正如你可以看到我已经创建MethodChannel名为CIFilterFactory 这意味着将来需要使用快速代码创建一个具有相同名称的通道以使其正常运行。 因为我需要项目列表,所以我使用invokeListMethod 。 这是通用方法,因此我们需要指定通用类型,否则由于项目将属于dynamic类型,因此会出现强制转换错误。 所有与错误处理有关的东西,我都留给以后使用。

To work effectively with Swift code you need Xcode. So open the project inside of example/ios directory and keep working in it if you need to do changes in Swift code. What is more, notice that you may not see console outputs if you run an application not from Xcode. All in all, if plan to print something in Swift launch application from Xcode. I’ve created a new file in ios/ClassesNativeFilter+factory.swift. Swift is close in coding rules like Dart, you don’t need that names of swift files to match classes’ names inside.

为了有效地使用Swift代码,您需要Xcode。 因此,如果需要在Swift代码中进行更改,请打开example/ios目录中的项目并继续在其中工作。 此外,请注意,如果您不是从Xcode运行应用程序,则可能看不到控制台输出。 总而言之,如果计划从Xcode在Swift启动应用程序中打印某些内容。 我在ios/Classes创建了一个新文件— NativeFilter+factory.swift 。 Swift在Dart之类的编码规则中非常接近,您不需要swift文件的名称即可与内部的类名称匹配。

When you add a new swift file you need to go to your example project and install pods to make it available in it.

当您添加新的swift文件时,您需要转到示例项目并安装pod使其在其中可用。

cd exmaple/ios
pod install

To open the newly created file in Xcode open Pods/Development Pods/native_filters/../../example/ios/.symlinks/plugins/native_filetrs/ios/Classes/.

要在Xcode中打开新创建的文件,请打开Pods/Development Pods/native_filters/../../example/ios/.symlinks/plugins/native_filetrs/ios/Classes/.

Image for post

All native classes that we are going to use with Dart code have to be inherited from NSObject. init method is analog of constructor in Dart. FlutterBinaryMessenge is responsible for serializing data in the channel. As you may notice, I’ve created a channel with the same name as in Dart. That’s how we defined that NativeFilterFactory will handle calls from Flutter.

我们将与Dart代码一起使用的所有本机类都必须从NSObject继承。 init方法与Dart中的构造函数类似。 FlutterBinaryMessenge负责序列化通道中的数据。 您可能会注意到,我创建了一个与Dart中相同名称的频道。 这就是我们定义NativeFilterFactory将处理Flutter的调用的方式。

Also, I’ve defined function to handle incoming messages from the Dart code. The first parameter contains message information, like the name of the invoked method and arguments. We need to compare the method with expected avaialbleFilters string and do necessary logic if it matches. FlutterResult is a function you need to invoke to submit the result back to Dart. You need to invoke it in any case to complete theFuture. If you want to return an error, you need to pass FlutterError instance.

另外,我定义了处理来自Dart代码的传入消息的函数。 第一个参数包含消息信息,例如被调用方法的名称和参数。 我们需要将该方法与预期的avaialbleFilters字符串进行比较,并在匹配时执行必要的逻辑。 FlutterResult是您需要调用以将结果提交回Dart的函数。 无论如何,您都需要调用它来完成Future 。 如果要返回错误,则需要传递FlutterError实例。

We need to register our factory in the plugin to make everything works. Open swift plugin file in the same folder and let’s do all necessary changes. We need init to create initialize our factory. As before this init will receive messenger. FlutterPlugin requires handle function to be defined in the descendant. I’ve removed old code from it redirect invocation to the factory function. Also, I’ve updated the register function. addMethodCallDelegate binds call from Dart to the native handler.

我们需要在插件中注册我们的工厂才能使一切正常。 在同一文件夹中打开swift插件文件,然后进行所有必要的更改。 我们需要使用init来初始化工厂。 和以前一样,此init将收到Messenger。 FlutterPlugin要求在后代中定义handle功能。 我已从其中删除了旧代码,将调用重定向到工厂功能。 另外,我已经更新了register功能。 addMethodCallDelegate将Dart的调用绑定到本机处理程序。

Actually, that’s all, our plugin now can return a list of available filters from Core Image. Let’s create some simple screen to display this information. It’s a simple StatefulWidget where during state initialization I load a list of filters and display them in ListView.

实际上,仅此而已,我们的插件现在可以从Core Image返回可用过滤器的列表。 让我们创建一个简单的屏幕来显示此信息。 这是一个简单的StatefulWidget ,在状态初始化期间,我会加载一系列过滤器并将其显示在ListView

Image for post

The list can be slightly different if you launch it on other devices than I do but changes won't be so critical.

如果您在其他设备上启动该列表,则该列表可能会与我稍有不同,但是更改并不是那么关键。

For more details look in the repository and the package, of course.

有关更多详细信息,请查看存储库软件包

Summary

摘要

I’ve created a new plugin project and implemented functionality to obtain a list of filters. Of course, it’s not enough to publish a package, that’s why you have to keep reading.

我创建了一个新的插件项目,并实现了获取过滤器列表的功能。 当然,仅仅发布一个包是不够的,这就是为什么你必须继续阅读

翻译自: https://medium.com/@nikolay.dymura/flutter-plugin-story-part-1-core-image-filters-support-in-flutter-15055ce8a85e

flutter image

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值