AppleのSwift Package Managerを使用してライブラリを出荷したいのですが、私のライブラリには、複数の文字列が異なる言語に翻訳された.bundleファイルが含まれています。cocoapodsを使用すると、spec.resourceを使用してそれを含めることができます。しかし、SwiftPMではできません。
パッケージマネージャーには、リソースをターゲットにバンドルする方法の定義がまだありません。これの必要性は認識していますが、具体的な提案はまだありません。私は https://bugs.Swift.org/browse/SR-2866 を提出して、これを追跡するバグがあることを確認しました。
フレームワークバンドルがサポートされていないためまだであり、SPMターゲットでバンドルアセットを提供する唯一の方法は、バンドルを使用することです。フレームワークにコードを実装して、メインプロジェクト(アセットバンドルをサポート)内の特定のバンドルを検索する場合、そのバンドルからリソースをロードできます。
例:
バンドルされているリソースにアクセスします。
extension Bundle {
static func myResourceBundle() throws -> Bundle {
let bundles = Bundle.allBundles
let bundlePaths = bundles.compactMap { $0.resourceURL?.appendingPathComponent("MyAssetBundle", isDirectory: false).appendingPathExtension("bundle") }
guard let bundle = bundlePaths.compactMap({ Bundle(url: $0) }).first else {
throw NSError(domain: "com.myframework", code: 404, userInfo: [NSLocalizedDescriptionKey: "Missing resource bundle"])
}
return bundle
}
}
バンドルされたリソースを利用する:
let bundle = try! Bundle.myResourceBundle()
return UIColor(named: "myColor", in: bundle, compatibleWith: nil)!
ストーリーボード、xibs、画像、色、データblob、さまざまな拡張子のファイル(json、txtなど)を含むがこれらに限定されないすべてのリソースファイルに同じロジックを適用できます。
注:これが意味のある場合もあれば、意味のない場合もあります。プロジェクトの裁量権を使用するかどうかを決定します。 Storyboards/Xibsをバンドルされたアセットに分離することを正当化するには、非常に具体的なシナリオが必要です。
これに使用する解決策は、必要なデータをSwiftオブジェクトに構築することです。このために、入力ファイルを読み取り、base64でエンコードしてから=を書き込むシェルスクリプトを用意しています。 SwiftファイルをInputStreamとして表示するファイルです。次に、データアイテムをmy Swiftパッケージに追加する場合、スクリプトを実行してファイルを読み取り、出力ファイルを書き込みます。もちろん、スクリプトがない場合でもプロジェクトを使用するユーザーがリソースを利用できるように、出力ファイルをチェックインする必要があります(通常、入力ファイルをResources
ディレクトリに配置して、 Sources
ディレクトリに出力されますが、スクリプト自体はそれに依存しません。)
私はこれを理想的なソリューションとは言い難く、パッケージマネージャーにこの機能が組み込まれるのを楽しみにしています。
次の例は、その使用方法を示しています。
まず、スクリプト自体は次のとおりです。
#!/usr/bin/env bash
# Read an input file, base64 encode it, then write an output Swift file that will
# present it as an input stream.
#
# Usage: generate_resource_file.sh <inputfile> <outputfile> <streamName>
#
# The <streamName> is the name presented for the resulting InputStream. So, for example,
# generate_resource_file.sh Resources/logo.png Sources/Logo.Swift logoInputStream
# will generate a file Sources/Logo.Swift that will contain a computed variable
# that will look like the following:
# var logoInputStream: InputStream { ...blah...
#
set -e
if [ $# -ne 3 ]; then
echo "Usage: generate_resource_file.sh <inputfile> <outputfile> <streamName>"
exit -1
fi
inFile=$1
outFile=$2
streamName=$3
echo "Generating $outFile from $inFile"
echo "Stream name will be $streamName"
if [ ! -f "$inFile" ]; then
echo "Could not read $inFile"
exit -1
fi
echo "// This file is automatically generated by generate_resource_file.sh. DO NOT EDIT!" > "$outFile"
echo "" >> "$outFile"
echo "import Foundation" >> "$outFile"
echo "" >> "$outFile"
echo "fileprivate let encodedString = \"\"\"" >> "$outFile"
base64 -i "$inFile" >> "$outFile"
echo "\"\"\"" >> "$outFile"
echo "" >> "$outFile"
echo "var $streamName: InputStream {" >> "$outFile"
echo " get {" >> "$outFile"
echo " let decodedData = Data(base64Encoded: encodedString)!" >> "$outFile"
echo " return InputStream(data: decodedData)" >> "$outFile"
echo " }" >> "$outFile"
echo "}" >> "$outFile"
echo "Rebuilt $outFile"
次に、ここに示す入力ファイルt.dat
を指定します。
Hello World!
コマンドgenerate_resource_file.sh t.dat HelloWorld.Swift helloWorldInputStream
を実行すると、次のHelloWorld.Swift
ファイルが生成されます。
// This file is automatically generated by generate_resource_file.sh. DO NOT EDIT!
import Foundation
fileprivate let encodedString = """
SGVsbG8gV29ybGQhCgo=
"""
var helloWorldInputStream: InputStream {
get {
let decodedData = Data(base64Encoded: encodedString)!
return InputStream(data: decodedData)
}
}