This is the third day of my participation in the August More text Challenge. For details, see:August is more challenging

preface

If you’re not sure what ODR: On-demand Resources is, check out Apple’s official resource reduction plan, ODR (1) : First Look

Now that you know what the ODR can do, take a shot at your own project. I use my personal project dream account here, and since there are multiple sets of skins that can be replaced in the project, there are many sets of ICONS saved, which are suitable for optimization using the ODR.

About THE ODR in addition to the official document, also did not find a lot of practical information, here combined with the document, hand touch hand and everyone to practice a wave of it.

Let’s start with a seller show

Before using the ODR

After using the ODR!

The size of the download on TestFlight has not yet been approved for release on 2.7.1 as of this writing, but it will not differ much from the actual download.

Enable the ODR

It’s on by default since iOS9

Create a label

Tags are used to identify and manage a set of ODRs. Assigning one or more tags to a resource in a project identifies it as an ODR. At run time, access to all Odrs works with labels rather than individual resources.

You can see the entry point for adding a tag in Target’s Resource tags, where you can select the resources in the project to add to the tag.

Resource organization before the project:

In order to facilitate label management, we split the resource bundle:

2.1 Add a tag to Assets

Add Assets to Tag:

2.2 Confirm that the resource label is set successfully

Open the resource bundle to view the resource information, and you can see the matching resource label here. (Multiple tags can be set for a resource)

When building a project, Xcode checks all tagged projects in the project and generates resource bundles for use by the operating system.

2.3 Quickly Adding a Label to a Resource

You can also quickly add an existing label to a single resource or quickly create a label by entering Lenovo directly.

Three, label classification

By switching to Prefetched, we see three categories:

The default category for labels created is to download the ODR on demand only. Labels can be dragged between categories.

  • Initial install tags.
    • Resources are downloaded at the same time as applications. The size of the resource is included in the total size of the application in the app store. When there’s nothingNSBundleResourceRequestIt may be cleared when accessed.
  • Prefetch tag order.
    • After the application is installed, resources are downloaded. Download in label order.
  • Dowloaded only on demand.
    • Load on demand. These tags are downloaded when the request is applied.

When the operating system downloads a label, it only downloads resources that are not available on the device.

3.1 Setting label Categories

Setting up a label category is as simple as dragging from the default ODR list to the corresponding category.

Here I set the default resource for both skins to Initial install

Four, size limit

After shearing is applied, the total size of resources in the label cannot exceed 512 MB. The total size of on-demand resources stored in the app store must not exceed 20 GB.

The ideal size of the label is not greater than 64 MB. This size provides a good balance between download speed and local storage, so that it can be cleared if the device’s local storage is low.

  • Slicing.
    • Check tags (✓) indicate that the size reflects the clipping size of the application.
  • App bundle.
    • Size of the clipped application package downloaded to the device.
  • Asset packs.
    • Asset packages are generated by Xcode.
  • Initial install tags.
    • The mark is the total cut size of the mark for the initial installation.
  • Initial install and prefetched tags.
    • Marked asInitial installPrefetch tagThe total size of the resource after shearing
  • In use on-demand resources.
    • One row at most is availableODRThe shear size of.
  • Hosted on-demand resources.
    • allODRSize, uncut size.

5. Manage ODR

After configuring the label, run the project directly. You can see that none of the ODR resources have been downloaded.

5.1 Determining the ODR update time

Here’s a description of the dream account skin logic to help determine when to update the ODR:

  • Skin is divided into two modes: Normal mode and Dark mode.
    • That is, the user can set the skin for the two modes, and the dark mode switch can be switched seamlessly
  • Setting the skin will reset the root controller
    • Here is a node where the ODR needs to be updated
  • Another node to check for updates is when the application starts
    • Check the current two skins and prepare resources for related labels

5.1 NSBundleResourceRequest Requests resources

A tag can be managed by multiple instances. Here are three important apis.

Initialize the

  • Tags: Collections of tags
  • Bundle: Usually main
public init(tags: Set<String>, bundle: Bundle)
Copy the code

Check the status

Check whether all the resources for the requested label have been saved in the device.

open func conditionallyBeginAccessingResources(completionHandler: @escaping (Bool) - >Void)
Copy the code

Start requesting resources

Request a tag resource that is not local.

open func beginAccessingResources(completionHandler: @escaping (Error?). ->Void)
Copy the code

Vi. Transformation of “Dream account book”

6.1 packaging OdrTool

protocol OdrTagProtocol {
    var tagName: String { get}}struct OdrTool {
    static func requestODR(of tags: OdrTagProtocol. .in bundle: Bundle = Bundle.main) {
        var tagsSet: Set<String> = []
        tags.forEach { tagsSet.insert($0.tagName) }
        let request = NSBundleResourceRequest(tags: tagsSet, bundle: bundle)
        request.conditionallyBeginAccessingResources { hasCache in
            if hasCache = = false {
                // These resources are not all local
                request.beginAccessingResources { error in
                    if let _ = error {
                        // Download failed
                    }
                    else {
                        // Download succeeded}}}else {
                // These resources are already local}}}}Copy the code

6.2 Expand Odr for AppearanceStyle skin system

AppearanceStyle is the core of the entire skin dressing system, and the body is an enumeration.

  • In this case, make the original skin match the name of your label.
  • And then add areloadOdrMethod to update the current two skinsODR
extension AppearanceStyle: OdrTagProtocol {
    static func reloadOdr(a) {
        OdrTool.requestODR(of: currentLightStyle, currentDarkStyle)
    }
    
    var tagName: String {
        switch self {
        case .Charge.ChargeMain:
            return "Charge"
        case .ChargeLight:
            return "ChargeLight"
        case .Eternal.Hachimitsu:
            return "Eternal"
        case .Spark:
            return "Sakura"
        case .SparkMain:
            return "Spark"
        case .NYXL:
            return "NYXL"
        case .Justice.Dream.Phoenix:
            return "Justice"
        case .Kiwi:
            return "Kiwi"
        case .Banshee:
            return "Banshee"
        case .Punk:
            return "Punk"}}}Copy the code

6.3 Updating Odr Resources on Appropriate Nodes

Node 1: The application starts

AppearanceStyle.reloadOdr()
Copy the code

Node 2: Set the skin

static func reloadApp(a) {
    guard let tabVC = UIStoryboard(name: "Home", bundle: nil).instantiateInitialViewController() else {
        return
    }
    UIApplication.shared.windows.filter { $0.isKeyWindow }.first?.rootViewController = tabVC
    reloadOdr()
}
Copy the code

6.4 Run the project and check the effect

Xcode shows that the resources for the two skins I set have been downloaded.

But open the App and it’s still blank?

6.5 Troubleshooting

As previously understood, ODR resources are cleaned up if they are not used by any NSBundleResourceRequest. The wrapper above does not hold an NSBundle of properties. Make some changes to the code.

OdrTool

struct OdrTool {
    static func requestODR(of tags: OdrTagProtocol. .in bundle: Bundle = Bundle.main) -> NSBundleResourceRequest {
        .
        let request = NSBundleResourceRequest(tags: tagsSet, bundle: bundle)
        .
        // Throw NSBundleResourceRequest
        return request
    }
}
Copy the code

AppearanceStyle

extension AppearanceStyle: OdrTagProtocol {
    // Add a static variable to save
    static var odrRequest: NSBundleResourceRequest?
    
    static func reloadOdr(a) {
        odrRequest = OdrTool.requestODR(of: currentLightStyle, currentDarkStyle)
    }
    
    var tagName: String {
        switch self {
            .}}}Copy the code

6.6 Checking the Modification Effect

Perfect ~ also tested the function of switching skin is no problem

If you look at Xcode, the status of the tags is different. The two tags that are In use are now In use.

6.7 Do I Need to Change the Resource Usage?

Don’t have to

Seven,

The experience is still very smooth, feel access cost is not high. I am quite familiar with my personal project, and the skin peeling system is well sealed 😜 also brings great convenience to access ODR. And my single skin resources only about 2M download is also very fast.

It might not be as simple as what I’m dealing with if it’s a larger resource load. And there are a lot of Settings that I don’t use in NSBundleResourceRequest, so if you want to know more about it, you can read the official documentation, so I’ll just throw a brick here 🧱.

And any choice of optimization program should be combined with the actual project, can copy the program is not exist. Apple’s ODR is good, but I feel that it has not entered the broad view of iOSer, it is a pity, if it feels right for your project can really use oh ~

👋 Bye ~

  • Wechat: RyukieW
  • 📦 Technical article archive
  • 🐙 making
My personal project Mine Elic endless sky ladder Dream of books
type The game financial
AppStore Elic Umemi

reference

  • ODR (1) : First look
  • What is app thinning? (iOS, tvOS, watchOS)
  • On-Demand Resources Guide