Implementing thermal updates for resource files such as iOS pictures (iv): A minimized patch update logic

Source: Internet
Author: User
Tags erro file url uikit install cocoapods

Brief introduction

Previously wrote a patch-updated article, where a more streamlined minimization implementation would be done to facilitate integration. To make the logic universal, the dependency on afnetworking and Reativecocoa will be stripped. The original article, you can see here:/http www.ios122.com/2015/12/jspatconline/

The meaning of doing so

First explain the motive and meaning, perhaps should become one of the standard framework of their own blog content, or later I need to look at, but also a bunch of withered code. Basic logic diagram, as above!

There are 3 reasons for simplicity:

    1. Patch update, the state can be designed very complex, as the beginning of the article mentioned, but I do not feel much need, at least in our app;
    2. I want to demonstrate a relatively complete logic, but do not want to spend too much time to build the scene;
    3. Simple, but sufficient, at least for our project at present;

So: the meaning of this article is actually to simplify the existing hot update code, the simpler the better maintenance.

Basic ideas
    1. When the app starts, it determines whether the image URL returned by the particular server interface is up-to-date, judging by whether the MD5 field in the return value is the same as the URL of the locally saved resource;
    2. If the image resources are updated, the download is extracted to the specified cache directory, the initial intention is to use the resource file MD5 to partition folders, to avoid conflicts;
    3. When reading a picture, the priority is read from the cache directory, the cache directory does not exist and is read from the IPA resource bundle;

Here's a step-by-step implementation.

When the app starts, determine if there are any latest picture resources

Here are the possible technical points that are mainly involved:

1. How do I send network requests using the underlying Network class library?

The first simple encapsulation of a function to obtain, using the Block.block often used, but to now do not remember the form, most of the copy from other places, and then change the parameters. Can't remember, too lazy to remember!

-(void) Fetchpatchinfo: (NSString *) urlstr Completionhandler: (void (^) (nsdictionary * patchinfo, Nserror * error)) completionhandler{nsurlsessionconfiguration * Defaultconfigobject = [nsurlsessionconfiguration    Defaultsessionconfiguration]; Nsurlsession * defaultsession = [nsurlsession sessionwithconfiguration:defaultconfigobject delegate:self    Delegatequeue: [Nsoperationqueue Mainqueue]];    Nsurl * url = [Nsurl urlwithstring:urlstr]; Nsurlsessiondatatask * Datatask = [Defaultsession datataskwithurl:url C                                                        ompletionhandler:^ (NSData * data, Nsurlresponse * response, Nserror * error) {                                                        Nsdictionary * Patchinfo = [nsjsonserialization jsonobjectwithdata:data options:0 error:&error];;                                                    Completionhandler (Patchinfo, error);    }]; [Datatask resume];}

Based on block, the code that is called is simply a simple answer.

[Self Fetchpatchinfo: @ "Https://raw.githubusercontent.com/ios122/ios_assets_hot_update/master/res/patch_04.json" completionhandler:^ (Nsdictionary * patchinfo, Nserror * error) {     if (! Error) {         NSLog (@ "patchinfo:%@", Patchinfo );     } else     {         NSLog (@ "Fetchpatchinfo error:%@", error);}     ];

Well, I admit afnetworking used to, for a long time useless original network request code, a little low, MO strange!

2. How to verify the MD5 value of downloaded files, if you need to?

The beginning of the article link, there is mentioned. The core, in fact, is to download the file, the MD5 value of the calculation, the remaining is the string comparison operation.

Note to introduce the system library first

#include <CommonCrypto/CommonDigest.h>

/** *  Gets the MD5 information for the file. * *  @param path file. * *  The MD5 value of the @return file. */-(NSString *) Mcmd5hashofpath: (NSString *) path{    Nsfilemanager * FileManager = [Nsfilemanager Defaultmanager];    Ensure that the file exists.    if ([FileManager fileexistsatpath:path Isdirectory:nil])    {        NSData * data = [NSData Datawithcontentsoffile:path ];        unsigned char digest[cc_md5_digest_length];        CC_MD5 (Data.bytes, (Cc_long) Data.length, Digest);        nsmutablestring * output = [nsmutablestring stringwithcapacity:cc_md5_digest_length * 2];        for (int i = 0; i < cc_md5_digest_length; i++)        {            [Output appendformat:@ "%02x", Digest[i]];        }        return output;    }    else    {        return @ "";    }}

3. What do I use to save and get information about the MD5 of local cache resources?

Well, I'm going to use the user profile directly,

NSString * Source_patch_key = @ "Source_patch"; [[Nsuserdefaults Standarduserdefaults] setobject:patchinfo forkey:source_patch_key];p atchinfo = [[NSUserDefaults Standarduserdefaults] Objectforkey:source_patch_key]; NSLog (@ "patchinfo:%@", patchinfo);

Patch Download and Unzip

Here are the possible technical points that are mainly involved:

1. How can I find the specified cache directory based on the image cache information?

The problem itself some of the mouth, in fact, I want to do is based on the patch MD5, put to a different cache folder, such as Patch MD5 for e963ed645c50a004697530fa596f180b, then the corresponding put to patch/ e963ed645c50a004697530fa596f180b folder. Encapsulates a simple way to return a cache path based on the MD5:

-(NSString *) Cachepathfor: (NSString *) patchmd5{    nsarray * librarypaths = Nssearchpathfordirectoriesindomains ( Nslibrarydirectory, Nsuserdomainmask, YES);    NSString * CachePath = [[[Librarypaths objectatindex:0] stringbyappendingformat:@ "/caches/patch"] STRINGBYAPPENDINGPATHCOMPONENT:PATCHMD5];    return CachePath;}

When used, it looks like this:

NSString * Urlstr = [Patchinfo objectforkey: @ "url"]; [Weak_self downloadfilefrom:urlstr completionhandler:^ (nsurl * location, Nserror * error) {    if (error) {        NSLog (@ "Download file url:%@  error:%@", URLSTR, error);        return;    }    NSString * CachePath = [weak_self cachepathfor: [Patchinfo objectforkey:@ "MD5"]];    NSLog (@ "location:%@ cachepath:%@", location, CachePath);}];

2. How do I unzip a file to a specified directory?

If you need to install CocoaPods, we recommend using brew :

Brew Install CocoaPods

Decompression itself recommended ssziparchive Library, a line of code to fix:

[Ssziparchive unzipFileAtPath:location.path todestination:patchcachepath overwrite:yes password:nil error:& ERROR];

3. When do I update the information about the local cache resource?

The recommendation is to download and unzip the resource file to the specified cache directory, and then update the relevant cache information for the patch, because this information, when reading the picture, is also required. If you delete a patch, according to the current design, a more lazy scenario is to put a new empty resource file on the server.

NSString * Source_patch_key = @ "Source_patch"; [[Nsuserdefaults Standarduserdefaults] Setobject:patchinfo Forkey:source_patch_key];

Read Image feature Extensions

Here are the possible technical points that are mainly involved:

1. How do I download files using the Base Network library?

Still is to encapsulate a simple function, after the download is completed, through the block outgoing file temporary save location:

-(void) Downloadfilefrom: (NSString *) urlstr Completionhandler: (void (^) (Nsurl *location, Nserror * error)) Completionha ndler{    nsurl * url = [Nsurl urlwithstring:urlstr];    Nsurlsessionconfiguration * Defaultconfigobject = [nsurlsessionconfiguration defaultsessionconfiguration];    Nsurlsession * defaultsession = [nsurlsession sessionwithconfiguration:defaultconfigobject delegate:self Delegatequeue: [Nsoperationqueue Mainqueue]];    Nsurlsessiondownloadtask * downloadtask =[defaultsession downloadtaskwithurl:url                                                                completionHandler:^ (NSURL * Location, Nsurlresponse * response, Nserror * error)                                              {                                                  completionhandler (location,error);                                              }];    [Downloadtask resume];}

2. How can I tell if a file is included in the bundle?

You can use Fileexistsatpath, but actually use -pathforresource:oftype: That's enough, because you can't find the resource when asked to add you, it returns nil, so we call it directly, and then determine whether the return is Nil can:

NSString * Imgpath = [mainbundle pathforresource:imgname oftype:@ "png"];

3. How does the code merge with the original imagenamed: Logic?

No need for initial copy to cache directory + initial request for latest resource patch Information + code migration Merge + interface optimization

A relatively complete logic code

Note that, according to the current design, you do not need to initially copy the original IPA bundle into the cache directory, when there is no related resources in the cache directory, will automatically try to read from the bundle in the IPA, bundle Convention Unified use Main.bundle to simplify the operation,

Category, external exposure two methods:

#import <UIKit/UIKit.h> @interface UIImage (imagenamed_bundle_)/* load img smart. */+ (UIImage *) yf_imagenamed: ( NSString *) imgname;/* Smart update for Patch */+ (void) Yf_updatepatchfrom: (NSString *) pathinfourlstr; @end

When the app starts up, or in other appropriate places, be aware of any updates that are checked:

-(BOOL) Application: (UIApplication *) application didfinishlaunchingwithoptions: (Nsdictionary *) launchOptions {    Override point for customization after application launch.    /* Fetch PATHC info every time */    NSString * patchurlstr = @ "Https://raw.githubusercontent.com/ios122/ios_assets_hot _update/master/res/patch_04.json ";    [UIImage Yf_updatepatchfrom:patchurlstr];    return YES;}

Internal implementations, optimized for many, but also not complex:

#import "Uiimage+imagenamed_bundle_.h" #import <SSZipArchive.h> @implementation UIImage (imagenamed_bundle_) + ( NSString *) yf_sourcepatchkey{return @ "Source_patch";} + (void) Yf_updatepatchfrom: (NSString *) pathinfourlstr{[self yf_fetchpatchinfo:pathinfourlstr completionhandler : ^ (nsdictionary *patchinfo, Nserror *error) {if (error) {NSLog (@ "Fetchpatchinfo error:%@", Erro               R);           Return           } NSString * Urlstr = [Patchinfo objectforkey: @ "url"];           NSString * MD5 = [patchinfo objectforkey:@ "MD5"]; NSString * ORIMD5 = [[[Nsuserdefaults Standarduserdefaults] Objectforkey: [self Yf_sourcepatchkey]] objectforkey:@ "MD5"           ];           if ([OriMd5 isequaltostring:md5]) {//no update return; } [Self Yf_downloadfilefrom:urlstr completionhandler:^ (nsurl *location, Nserror *error) {if (Erro R) {NSLog (@ "Download file url:%@ Error:%@", Urlstr, ErroR);               Return               } NSString * Patchcachepath = [self yf_cachepathfor:md5]; [Ssziparchive unzipFileAtPath:location.path todestination:patchcachepath overwrite:yes password:nil error:&               ERROR];                   if (Error) {NSLog (@ "Unzip and move file error, with urlstr:%@ error:%@", URLSTR, error);               Return }/* Update patch info.               */NSString * Source_patch_key = [self yf_sourcepatchkey];           [[Nsuserdefaults Standarduserdefaults] Setobject:patchinfo Forkey:source_patch_key];       }]; }];} + (NSString *) Yf_relativecachepathfor: (NSString *) md5{return [@ "patch" STRINGBYAPPENDINGPATHCOMPONENT:MD5];}    + (UIImage *) yf_imagenamed: (NSString *) imgname{NSString * bundlename = @ "main"; /* Cache dir */nsstring * MD5 = [[[[Nsuserdefaults Standarduserdefaults] Objectforkey: [self Yf_sourcepatchkey]] Object    forkey:@ "MD5"]; NSString * rElativecachepath = [self yf_relativecachepathfor:md5]; return [self yf_imagenamed:imgname bundle:bundlename cachedir:relativecachepath];} + (UIImage *) yf_imagenamed: (NSString *) imgname Bundle: (NSString *) bundlename cachedir: (NSString *) cachedir{Nsarray * L    Ibrarypaths = Nssearchpathfordirectoriesindomains (Nslibrarydirectory, Nsuserdomainmask, YES);    Bundlename = [NSString stringwithformat:@ "%@.bundle", Bundlename];    NSString * Ipabundledir = [NSBundle mainbundle].resourcepath;    NSString * Cachebundledir = Ipabundledir; if (cachedir) {cachebundledir = [[[[Librarypaths objectatindex:0] stringbyappendingformat:@ "/caches"] StringByAppen    Dingpathcomponent:cachedir];    } imgname = [NSString stringwithformat:@ "%@@3x", imgname];    NSString * Bundlepath = [Cachebundledir stringbyappendingpathcomponent:bundlename];    NSBundle * Mainbundle = [NSBundle Bundlewithpath:bundlepath];    NSString * Imgpath = [mainbundle pathforresource:imgname oftype:@ "png"]; /* Try LoadFrom ipa! */if (! Imgpath &&!) [Ipabundledir Isequaltostring:cachebundledir])        {Bundlepath = [ipabundledir stringbyappendingpathcomponent:bundlename];        Mainbundle = [NSBundle Bundlewithpath:bundlepath];    Imgpath = [Mainbundle pathforresource:imgname oftype:@ "png"];    } UIImage * image;    Static NSString * model;    if (!model) {model = [[Uidevice Currentdevice]model];        } if ([Model isequaltostring:@ "IPad"]) {NSData * imageData = [NSData Datawithcontentsoffile:imgpath];    Image = [UIImage imagewithdata:imagedata scale:2.0];    }else{image = [UIImage Imagewithcontentsoffile:imgpath]; } return image; + (void) Yf_fetchpatchinfo: (NSString *) urlstr Completionhandler: (void (^) (nsdictionary * patchinfo, Nserror * error)) completionhandler{nsurlsessionconfiguration *defaultconfigobject = [nsurlsessionconfiguration    Defaultsessionconfiguration]; Nsurlsession *defaultsession = [Nsurlsession SessionwithconfiguraTion:defaultconfigobject delegate:nil delegatequeue: [Nsoperationqueue Mainqueue]];    Nsurl * url = [Nsurl urlwithstring:urlstr]; Nsurlsessiondatatask * Datatask = [Defaultsession datataskwithurl:url C                                                        ompletionhandler:^ (NSData *data, Nsurlresponse *response, Nserror *error) {                                                        Nsdictionary * Patchinfo = [nsjsonserialization jsonobjectwithdata:data options:0 error:&error];;                                                    Completionhandler (Patchinfo, error);    }]; [Datatask resume];} + (void) Yf_downloadfilefrom: (NSString *) urlstr Completionhandler: (void (^) (Nsurl *location, Nserror * error)) Completi    onhandler{nsurl * url = [Nsurl urlwithstring:urlstr];    Nsurlsessionconfiguration *defaultconfigobject = [Nsurlsessionconfiguration defaultsessionconfiguration]; Nsurlsession *defaultsession = [nsurlsession sesSionwithconfiguration:defaultconfigobject delegate:nil delegatequeue: [Nsoperationqueue MainQueue]];                                                                Nsurlsessiondownloadtask * Downloadtask =[defaultsession Downloadtaskwithurl:url                                              completionhandler:^ (Nsurl *location, Nsurlresponse *response, Nserror *error)                                              {Completionhandler (location,error);    }]; [Downloadtask resume];} + (NSString *) Yf_cachepathfor: (NSString *) patchmd5{Nsarray * librarypaths = Nssearchpathfordirectoriesindomains (NSLib    Rarydirectory, Nsuserdomainmask, YES); NSString * CachePath = [[[Librarypaths objectatindex:0] stringbyappendingformat:@ "/caches"]    Stringbyappendingpathcomponent:[self YF_RELATIVECACHEPATHFOR:PATCHMD5]]; return CachePath;} @end

Now the code to load the picture is simpler:

UIImage * image = [UIImage yf_imagenamed:@ "sub/sample"];self.sampleimageview.image = image;

If the hot update takes effect, the running see should be a hammer picture:

Postscript

I think the most important feature of this article is that it is a complete record of the process of optimizing problem solving; The sample code looks somewhat less uniform, because: I did not have a plan to write a blog, but to use the blog itself to comb ideas, simplifying logic! So, blogging is not just a time-consuming process of sharing knowledge, It has become a powerful tool to help you think! like!!!

Reference resources:
    • This section is complete to execute Xcode engineering code, less than 100k
    • Series articles, exclusive GitHub projects
    • IOS nsurlsession Example (HTTP GET, POST, Background downlads)
    • Value 100W experience Sharing: Jspatch-based instant fix for iOS app online bug with source code.
    • Ziparchive is a simple utility class for zipping and unzipping files on IOS and Mac.
    • Installation and use of pods

Implementing thermal updates for resource files such as iOS pictures (iv): A minimized patch update logic

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.