Je voudrais expédier ma bibliothèque en utilisant le Swift Gestionnaire de paquets d'Apple. Cependant, ma bibliothèque comprend un fichier .bundle avec plusieurs chaînes traduites dans différentes langues. En utilisant des cocoapods, je peux l'inclure en utilisant spec.resource. Mais dans SwiftPM, je ne peux pas le faire. Une solution?
Le gestionnaire de packages n'a pas encore de définition de la façon dont les ressources seront regroupées avec les cibles. Nous en sommes conscients, mais nous n'avons pas encore de proposition concrète à ce sujet. J'ai déposé https://bugs.Swift.org/browse/SR-2866 pour nous assurer que nous avons un bug qui suit cela.
Étant donné que les bundles de framework ne sont pas pris en charge pour l'instant, la seule façon de fournir des actifs de bundle avec une cible SPM est via un bundle. Si vous implémentez du code dans votre framework pour rechercher un bundle particulier dans votre projet principal (support des bundles d'actifs), vous pouvez charger des ressources à partir de ce bundle.
Exemple:
Accédez aux ressources groupées:
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
}
}
Utilisez les ressources groupées:
let bundle = try! Bundle.myResourceBundle()
return UIColor(named: "myColor", in: bundle, compatibleWith: nil)!
Vous pouvez appliquer la même logique pour tous les fichiers de ressources, y compris, mais sans s'y limiter, les storyboards, les xibs, les images, les couleurs, les blobs de données et les fichiers de diverses extensions (json, txt, etc.).
Remarque: Parfois, cela a du sens, parfois non. Déterminez l'utilisation à la discrétion du projet. Il faudrait des scénarios très spécifiques pour justifier la séparation des Storyboards/Xibs en ressources groupées.
La solution que j'utilise pour cela est de construire les données dont j'ai besoin dans un objet Swift. À cette fin, j'ai un script Shell qui va lire un fichier d'entrée, le coder en base64, puis écrire un = Swift fichier qui le présente comme un InputStream. Ensuite, quand je veux ajouter un élément de données à mon Swift package, j'exécute le script pour lire le fichier et écrire le fichier de sortie. Bien sûr, le fichier de sortie doit être archivé pour que la ressource soit disponible pour ceux qui utilisent le projet même s'ils n'ont pas le script. (En général, je place mes fichiers d'entrée dans un Resources
et écrivez la sortie dans le répertoire Sources
, mais le script lui-même ne dépend pas de cela.)
Je considère que c'est une solution loin d'être idéale, et j'attends avec impatience le moment où le gestionnaire de paquets aura cette capacité intégrée. Mais en attendant, c'est une solution viable.
L'exemple suivant montre comment il est utilisé:
Tout d'abord, voici le script lui-même:
#!/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"
Puis, étant donné un fichier d'entrée t.dat
montré ici:
Hello World!
Exécution de la commande generate_resource_file.sh t.dat HelloWorld.Swift helloWorldInputStream
génère les éléments suivants HelloWorld.Swift
fichier:
// 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)
}
}