在 Flutter 插件的 IOS 组件中,在何处以及如何包含文件资源?
Where and How to Include File Resources Within IOS component of Flutter Plugin?
假设您正在 Swift.
中编写 Flutter 插件的 IOS 组件
您的 MyFlutterPlugin.swift 文件已在 XCode 中打开。
所以我们知道我们在谈论同一件事,文件看起来像这样:
public class MyFlutterPlugin: NSObject, FlutterPlugin {
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "my_flutter_plugin", binaryMessenger: registrar.messenger())
let instance = SwiftMetronomeFlutterPlugin()
registrar.addMethodCallDelegate(instance, channel: channel)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
// ...
}
}
此文件存在于磁盘上:
[your_plugin_project_name]/ios/classes/MyFlutterPlugin.swift
如何添加资源,例如音频 (WAV) 文件,以便在 MyFlutterPlugin.swift 中引用它?
在普通(非 Flutter)IOS 应用程序中,我只需将 WAV 文件拖到 XCode 与 ViewController.swift 并排的位置(在同一文件夹中)即可完成此操作,并从 ViewController 中引用它,如下所示:
let clack_Path = Bundle.main.path(forResource: "clack", ofType: "wav")
let clack_URL = URL(fileURLWithPath: clack_Path!)
但是,如果我在 MyFlutterPlugin.swift 中尝试相同的方法(将音频文件放在 MyFlutterPlugin.swift 旁边),我会得到一个错误,指出 clack_Path 为空。
那么放置文件的正确位置在哪里,以及如何正确引用它?
我找不到关于这个特定问题的任何代码示例、教程或文档(至少没有我认为有用的)。希望它实际上可以在 IOS 上做...我已经包含了资源并在插件的 Android 端工作。
试试这个:https://docs.flutter.dev/development/ui/assets-and-images#loading-flutter-assets-in-ios
简而言之,首先,将您的文件作为普通 Flutter 资产(而不是 ios/android 资产)。然后,使用link中的方法访问它。
为了能够在Flutter Plugin中使用assets,首先,我们需要在plugins的文件夹中添加资源,在这个例子中,我将clap.wav
文件放在文件夹[your_plugin_project_name]/ios/Assets/
.
在插件文件夹中添加文件后,we need to specify in the plugin's PodSpec where the assets are located。
# File [your_plugin_project_name]/my_flutter_plugin.podspec
Pod::Spec.new do |s|
# [...] supressed content above
s.source_files = 'Classes/**/*'
s.resources = ['Assets/**.*']
# [...] supressed content below
end
上面代码片段中的重要部分是 s.resources = ['Assets/**.*']
行,其中 Assets/**/*
指定插件的所有资源都在文件夹 Assets
中。 Assets/**/*
是一个通配符,用于指示文件夹 Assets
中每个 folder/subfolder(**
部分)中的每个文件(*
字符串部分)必须作为插件包的资源包含在内。您可以通过搜索 regular expression
.
了解更多有关此类字符串的信息
每次更改插件的配置时,都需要通知使用该插件的Flutter项目有新的更改。在常规项目中,您需要提升插件的版本并在 Pub 中发布它的新版本,但由于我们只是在本地更改它(不向世界发布),我们只需要通知Flutter 插件的文件已经过时了。最简单的方法是在使用插件的项目中 运行 flutter clean
。
之后,您将能够使用以下代码访问插件的 swift 文件中的 clap.wav
文件:
guard let url = Bundle(for: type(of: self)).url(forResource: "clap", withExtension: "wav") else {
return print("File not found")
}
请注意,您必须使用 Bundle(for: type(of: self))
而不是 Bundle.main
(Bundle.main
指向 Runner 的包而不是您的插件的包)。
在下面的示例中,我展示了如何使用 swift 代码播放 clap.wav
:
import Flutter
import UIKit
import AVFoundation
public class SwiftMyFlutterPlugin: NSObject, FlutterPlugin {
private var player: AVAudioPlayer?
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "my_flutter_plugin", binaryMessenger: registrar.messenger())
let instance = SwiftMyFlutterPlugin()
registrar.addMethodCallDelegate(instance, channel: channel)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
switch call.method {
case "getPlatformVersion":
return result("iOS " + UIDevice.current.systemVersion)
case "playSound":
return playSound(result: result)
default:
return result(FlutterMethodNotImplemented)
}
}
private func playSound(result: @escaping FlutterResult) {
if player?.isPlaying == true { return }
let filename = "clap"
let fileExtension = "wav"
guard let url = Bundle(for: type(of: self)).url(forResource: filename, withExtension: fileExtension) else {
let flutterError = FlutterError(
code: "fileNotFound",
message: "File not found: \(filename).\(fileExtension).",
details: nil
)
return result(flutterError)
}
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback)
try AVAudioSession.sharedInstance().setActive(true)
} catch {
let flutterError = FlutterError(
code: "audioSessionSetupError",
message: "Error on AVAudionSession setup.",
details: error.localizedDescription
)
return result(flutterError)
}
do {
player = try AVAudioPlayer(contentsOf: url)
player?.play()
} catch {
let flutterError = FlutterError(
code: "audioPlayerSetupError",
message: "Error on AVAudioPlayer setup.",
details: error.localizedDescription
)
return result(flutterError)
}
}
}
上面的例子是一个简单的例子,说明了如何播放 clap.wav
文件,但你可以用其他不同的方式来播放。由于这与问题无关,我认为上面的例子足以回答你的问题。
为了便于您理解并轻松证明上面的代码有效,我在 GitHub 中创建了一个简单的项目,您可以执行该项目以查看其是否按预期工作,see it here。
请注意,您必须 运行 文件夹 example
.
中的代码
假设您正在 Swift.
中编写 Flutter 插件的 IOS 组件您的 MyFlutterPlugin.swift 文件已在 XCode 中打开。
所以我们知道我们在谈论同一件事,文件看起来像这样:
public class MyFlutterPlugin: NSObject, FlutterPlugin {
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "my_flutter_plugin", binaryMessenger: registrar.messenger())
let instance = SwiftMetronomeFlutterPlugin()
registrar.addMethodCallDelegate(instance, channel: channel)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
// ...
}
}
此文件存在于磁盘上:
[your_plugin_project_name]/ios/classes/MyFlutterPlugin.swift
如何添加资源,例如音频 (WAV) 文件,以便在 MyFlutterPlugin.swift 中引用它?
在普通(非 Flutter)IOS 应用程序中,我只需将 WAV 文件拖到 XCode 与 ViewController.swift 并排的位置(在同一文件夹中)即可完成此操作,并从 ViewController 中引用它,如下所示:
let clack_Path = Bundle.main.path(forResource: "clack", ofType: "wav")
let clack_URL = URL(fileURLWithPath: clack_Path!)
但是,如果我在 MyFlutterPlugin.swift 中尝试相同的方法(将音频文件放在 MyFlutterPlugin.swift 旁边),我会得到一个错误,指出 clack_Path 为空。
那么放置文件的正确位置在哪里,以及如何正确引用它?
我找不到关于这个特定问题的任何代码示例、教程或文档(至少没有我认为有用的)。希望它实际上可以在 IOS 上做...我已经包含了资源并在插件的 Android 端工作。
试试这个:https://docs.flutter.dev/development/ui/assets-and-images#loading-flutter-assets-in-ios
简而言之,首先,将您的文件作为普通 Flutter 资产(而不是 ios/android 资产)。然后,使用link中的方法访问它。
为了能够在Flutter Plugin中使用assets,首先,我们需要在plugins的文件夹中添加资源,在这个例子中,我将clap.wav
文件放在文件夹[your_plugin_project_name]/ios/Assets/
.
在插件文件夹中添加文件后,we need to specify in the plugin's PodSpec where the assets are located。
# File [your_plugin_project_name]/my_flutter_plugin.podspec
Pod::Spec.new do |s|
# [...] supressed content above
s.source_files = 'Classes/**/*'
s.resources = ['Assets/**.*']
# [...] supressed content below
end
上面代码片段中的重要部分是 s.resources = ['Assets/**.*']
行,其中 Assets/**/*
指定插件的所有资源都在文件夹 Assets
中。 Assets/**/*
是一个通配符,用于指示文件夹 Assets
中每个 folder/subfolder(**
部分)中的每个文件(*
字符串部分)必须作为插件包的资源包含在内。您可以通过搜索 regular expression
.
每次更改插件的配置时,都需要通知使用该插件的Flutter项目有新的更改。在常规项目中,您需要提升插件的版本并在 Pub 中发布它的新版本,但由于我们只是在本地更改它(不向世界发布),我们只需要通知Flutter 插件的文件已经过时了。最简单的方法是在使用插件的项目中 运行 flutter clean
。
之后,您将能够使用以下代码访问插件的 swift 文件中的 clap.wav
文件:
guard let url = Bundle(for: type(of: self)).url(forResource: "clap", withExtension: "wav") else {
return print("File not found")
}
请注意,您必须使用 Bundle(for: type(of: self))
而不是 Bundle.main
(Bundle.main
指向 Runner 的包而不是您的插件的包)。
在下面的示例中,我展示了如何使用 swift 代码播放 clap.wav
:
import Flutter
import UIKit
import AVFoundation
public class SwiftMyFlutterPlugin: NSObject, FlutterPlugin {
private var player: AVAudioPlayer?
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "my_flutter_plugin", binaryMessenger: registrar.messenger())
let instance = SwiftMyFlutterPlugin()
registrar.addMethodCallDelegate(instance, channel: channel)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
switch call.method {
case "getPlatformVersion":
return result("iOS " + UIDevice.current.systemVersion)
case "playSound":
return playSound(result: result)
default:
return result(FlutterMethodNotImplemented)
}
}
private func playSound(result: @escaping FlutterResult) {
if player?.isPlaying == true { return }
let filename = "clap"
let fileExtension = "wav"
guard let url = Bundle(for: type(of: self)).url(forResource: filename, withExtension: fileExtension) else {
let flutterError = FlutterError(
code: "fileNotFound",
message: "File not found: \(filename).\(fileExtension).",
details: nil
)
return result(flutterError)
}
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback)
try AVAudioSession.sharedInstance().setActive(true)
} catch {
let flutterError = FlutterError(
code: "audioSessionSetupError",
message: "Error on AVAudionSession setup.",
details: error.localizedDescription
)
return result(flutterError)
}
do {
player = try AVAudioPlayer(contentsOf: url)
player?.play()
} catch {
let flutterError = FlutterError(
code: "audioPlayerSetupError",
message: "Error on AVAudioPlayer setup.",
details: error.localizedDescription
)
return result(flutterError)
}
}
}
上面的例子是一个简单的例子,说明了如何播放 clap.wav
文件,但你可以用其他不同的方式来播放。由于这与问题无关,我认为上面的例子足以回答你的问题。
为了便于您理解并轻松证明上面的代码有效,我在 GitHub 中创建了一个简单的项目,您可以执行该项目以查看其是否按预期工作,see it here。
请注意,您必须 运行 文件夹 example
.