The introduction
Since the update, SwiftPM has been plagued by the inability to add resource files to packages. This can cause a lot of trouble for developers who are used to using CocoaPods, but SwiftPM isn’t as bad as CocoaPods at the moment. SwiftPM is also aware of this and last year we saw github’s SwiftPM corresponding to repository API submissions such as Resource.
In this SwiftPM update, in addition to adding resource files as mentioned above, localization and other functions have also been added. The following describes the Session content on wwDC-2020.
Configuration requirements
The resource file management function of SwiftPM is swif-tool -version 5.3, which corresponds to Xcode 12. So the package.swift configuration needs to declare swift 5.3 above (this line is not a comment, but a required configuration for file parsing) :
Add and configure resource files
For some specific file types, such as the ones in the figure below. Developers don’t need to configure anything in package.swift because Xcode knows what these types of files stand for, for example.xcassets for images, color resources, xib for user interface files, etc.
For file types whose purpose is less clear (some of the file types in the figure below), you need to configure them in package.swift. For example, a plain text file may contain data that needs to be loaded at run time for calculation or presentation, or it may just be a developer document.
For files of unknown significance like the one above, you need to configure them according to the rules in the package.swift listing, using this GameLogin as an example:
- for
Media.xcasset
和main.storyboard
File, Xcode knows exactly what it represents, so it doesn’t need to be marked in this configuration file, right internal Note.txt
Files andArtwork Creation
The folder is an internal module file, so write intarget
的exclude
Property, so Xcode doesn’t compile it into the package- Files of other types that are not automatically recognized and need to be loaded into the package are configured in
resource
Attribute.
Here are some rules for configuring resource files. We can see that there are two static methods for the resource property: process() and copy(). According to session, process() is recommended, and the files configured are optimized for the platform used and the built-in rules. For example, convert storyboard or Asset Catalog to the appropriate form at runtime, including compressed images, etc. If the file type is not recognized or cannot be optimized for platform, it will simply be copied, that is, copy().
The build process
When an App uses a package, the package includes both source and resource files. During compilation, the source files of each target in the Package are first compiled into modules and linked to the App. Then the resource files of these targets are processed into bundles and put into these modules.
In Apple platform, App and App Extension are bundles. The bundles of these packages are part of the App, so they can be obtained at runtime without any other processing. When compiling to an unbundle artifact, such as a scripting tool, you need to load the resource bundle at the same time the script is started.
Accessing resource files
When you compile the Package with the resource files, a file resource_bundle_accessor.swift is automatically created and added to the Module, with contents roughly equivalent to the following: resource_bundle_accessor.swift
import Foundation
extension Bundle {
static let module = Bundle(path: "\(Bundle.main.bundlePath)/path/to/this/targets/resource/bundle")}Copy the code
You can use the following method for Swift and OC respectively, or you can use UIImage’s own Api with Bundle parameters
Because module is an internal property, this method can only access resource files within its own module, not across modules. If you want to provide resources in a public module that are used by external modules, you need to create your own resource accessor. Developers who have used Cocoapods’ resource_bundle feature will know this and can access it using the bundle path. If you don’t build a separate common resources module, you don’t need to worry so much.
localization
First you need to configure the default language in the configuration file:
let package = Package(
name: "MyLibrary",
defaultLocalization: "en",
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
],
dependencies: [
// Dependencies declare other packages that this package depends on.
/ / package (url: package / * * / url, from: "1.0.0"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
)
Copy the code
Then create a file named for the language you need, with a.lproj suffix, and create.strings or.stringsdict files in the folder, as shown below:
When using:
Button(action: roll, label: {
Text("Roll", bundle: Bundle.module)
.font(.title)
})
Copy the code
When testing, you can set the locale by declaring environment variables:
As you can see from the folder declaration, language internationalization requires the creation of a new folder with the suffix.lproj, which also fits the “file with purpose” statement above, so there is no need to configure additional properties in package.swift.
conclusion
This brief introduction mainly covers the process of adding local resource files and localization to the Package, with a few main points:
- For using purposeful files, such as
.xcassets
,.xib
、.storyboard
Files with suffixes, etc. do not need to be inpackage.swift
To add any configuration. - For files whose purpose is not clear, such as plain text files and script files, you can use the
package.swift
(the following are configurable for files and folders) :- For those that do not need to be referenced externally, such as internal developer documentation
README
, need to be configured intarget.excludes
Attribute. - For runtime, files that can be optimized by the system for the platform, such as various images, need to be configured in
target.resource.process
In the attribute - For runtime use, there are no optimized files, such as various images, that need to be configured in
target.resource.copy
In the attribute
- For those that do not need to be referenced externally, such as internal developer documentation
- The localization process requires first declaring the default language in the configuration file, and then creating from the language
.lproj
Folder, and then create in the folder.strings
or.stringsdict
File, write localized string.
In addition to the above, going back to Swift Package Manager itself, although it is improving day by day, I personally feel that it is really far from being widely used. Under the current environment, swift will basically replace OC to become the main native iOS development language in a few years in China, but there is no suitable reason for the whole environment to prevent cross-end development from gradually becoming the mainstream. From H5 to RN, WEEX, and now the FLUTTER, the performance gap has been slowly narrowed by mapping to hardware with optimized configurations, and the desired hot update to the business is not a technical issue. For the rest of Swift developers, how can SwiftPM convince them to use it instead of mature CocoaPods? An “official” label is not enough.
reference
- Swift packages: Resources and localization
- What is Bundle.module