iOS开发-实现获取下载主题配置动态切换主题

iOS开发-实现获取下载主题配置动态切换主题

iOS开发-实现获取下载主题配置更切换主题,主要是通过请求服务端配置的主题配置、下载主题、解压保存到本地。通知界面获取对应的图片及颜色等。

比如新年主题风格,常见的背景显示红色氛围图片、tabbar显示新年风格的按钮样式、导航条显示红色样式等。

一、主题Json对应的model

这里使用JsonModel将主题转成model

model代码如下

SDAppThemeConfigViewModel.h

objectivec 复制代码
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

/**
 Navigation主题样式
 */
@interface SDAppThemeConfigNavViewModel : NSObject

@property (nonatomic, strong) NSString *backgroundColor;
@property (nonatomic, strong) NSString *backgroundImage;

@property (nonatomic, strong) UIImage *t_backgroundImage;

@property (nonatomic, strong) NSString *btnImageColor;
@property (nonatomic, strong) NSString *btnTitleColor;
@property (nonatomic, strong) NSString *navTitleColor;

@property (nonatomic, strong) NSString *showLine;
@property (nonatomic, strong) NSString *lineColor;

@end

/**
 单个tab按钮样式
 */
@interface SDAppThemeConfigTabItemViewModel : NSObject

@property (nonatomic, strong) NSString *title;
@property (nonatomic, strong) NSString *titleColor;
@property (nonatomic, strong) NSString *selectedTitleColor;
@property (nonatomic, strong) NSString *icon;
@property (nonatomic, strong) NSString *selectedIcon;

@property (nonatomic, strong) UIImage *t_icon;
@property (nonatomic, strong) UIImage *t_selectedIcon;

@end

/**
 tabbar样式
 */
@interface SDAppThemeConfigTabViewModel : NSObject

@property (nonatomic, strong) NSString *backgroundColor;
@property (nonatomic, strong) NSString *backgroundImage;
@property (nonatomic, strong) NSString *showLine;
@property (nonatomic, strong) NSString *lineColor;
@property (nonatomic, strong) NSString *badgeBgColor;

@property (nonatomic, strong) UIImage *t_backgroundImage;

@property (nonatomic, strong) SDAppThemeConfigTabItemViewModel *lianlian;
@property (nonatomic, strong) SDAppThemeConfigTabItemViewModel *guangguang;
@property (nonatomic, strong) SDAppThemeConfigTabItemViewModel *message;
@property (nonatomic, strong) SDAppThemeConfigTabItemViewModel *shop;
@property (nonatomic, strong) SDAppThemeConfigTabItemViewModel *mine;

@end

/**
 将本地的主题config.json转成viewmodel
 */
@interface SDAppThemeConfigViewModel : NSObject

@property (nonatomic, strong) NSString *globalColor;
@property (nonatomic, strong) NSString *globalImage;
@property (nonatomic, strong) SDAppThemeConfigNavViewModel *navigation;
@property (nonatomic, strong) SDAppThemeConfigTabViewModel *tabbar;

@property (nonatomic, strong) UIImage *t_globalImage;

+ (SDAppThemeConfigViewModel *)themeViewModel:(NSString *)themeJson;

+ (SDAppThemeConfigViewModel *)defautThemeViewModel;

@end

SDAppThemeConfigViewModel.m

objectivec 复制代码
#import "SDAppThemeConfigViewModel.h"
#import <NSObject+YYModel.h>

/**
 Navigation主题样式
 */
@implementation SDAppThemeConfigNavViewModel

@end

/**
 单个tab按钮样式
 */
@implementation SDAppThemeConfigTabItemViewModel

@end

/**
 tabbar样式
 */
@implementation SDAppThemeConfigTabViewModel

@end

/**
 将本地的主题config.json转成viewmodel
 */
@implementation SDAppThemeConfigViewModel

+ (SDAppThemeConfigViewModel *)themeViewModel:(NSString *)themeJson {
    return [SDAppThemeConfigViewModel modelWithJSON:themeJson];
}

+ (SDAppThemeConfigViewModel *)defautThemeViewModel {
    SDAppThemeConfigViewModel *viewModel = [[SDAppThemeConfigViewModel alloc] init];
    SDAppThemeConfigNavViewModel *navConfigViewModel = [[SDAppThemeConfigNavViewModel alloc] init];
    navConfigViewModel.backgroundColor = @"171013";
    navConfigViewModel.btnImageColor = @"ffffff";
    navConfigViewModel.btnTitleColor = @"ffffff";
    navConfigViewModel.navTitleColor = @"ffffff";
    viewModel.navigation = navConfigViewModel;
    return viewModel;
}

@end

二、实现下载解压主题

2.1 AFNetworking下载

下载使用的是AFNetworking下载功能。AFNetworking是一个轻量级的iOS网络通信类库。

下载代码:

objectivec 复制代码
#pragma mark - Http download
/**
 请求下载
 
 @param aUrl aurl
 @param aSavePath aSavePath
 @param aFileName aFileName
 @param aTag aTag
 @param downloadprogress downloadprogress
 @param success success
 @param failure failure
 */
- (void)downloadFileURL:(NSString *)aUrl
               savePath:(NSString *)aSavePath
               fileName:(NSString *)aFileName
                    tag:(NSInteger)aTag
       downloadProgress:(void(^)(CGFloat progress))downloadprogress
                success:(void(^)(NSURLResponse *response,NSString *filePath))success
                failure:(void(^)(HttpError * e))failure {
    
    NSFileManager *fileManger = [NSFileManager defaultManager];
    
    if ([fileManger fileExistsAtPath:[aSavePath stringByAppendingPathComponent:aFileName]]) {
        //文件存在
        return;
    }
    
    //2.确定请求的URL地址
    NSString *requestUrl = [self requestUrlWithPath:aUrl clientType:HttpClientTypeWithOut];

    NSMutableURLRequest *request = [self.httpManager.requestSerializer requestWithMethod:@"GET" URLString:requestUrl parameters:nil error:nil];
    
    __block NSURLSessionDownloadTask *downloadTask = nil;
    
    downloadTask = [self.httpManager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) {
        dispatch_async(dispatch_get_main_queue(), ^{
            
            downloadprogress(1.0 * downloadProgress.completedUnitCount / downloadProgress.totalUnitCount);
        });
        
    } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
        return [NSURL fileURLWithPath:aSavePath];
        
    } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
        if(error == nil) {
            success(response,[filePath path]);
        } else {
            //下载失败
            NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
            HttpError *e = [self httpRequestFailure:httpResponse error:error];
            failure(e);
        }
    }];
    
    [downloadTask resume];
}

2.2 判断主题版本是否已经下载

在获取主题版本时候,需要判断主题是否存在,如果存在,则直接获取保存的地址。不存在,下载解压当前版本的主题包。

objectivec 复制代码
//判断当前主题版本号下是否存在资源文件夹
    BOOL curThemeExist = [self hasAppThemeVersion:themeModel.curVersion];
    if (!curThemeExist) {
        //如果不存在,重新下载解压
        __block NSString *saveZipPath = [self saveThemeTargetBasePath:themeModel.curVersion];
        __block NSString *themeUnZipPath = [self saveThemeDirBasePath:themeModel.curVersion];
        __block NSString *curDownloadurl = themeModel.curDownloadurl;
        //下载成功
        NSString *afileName = [[NSURL URLWithString:curDownloadurl] lastPathComponent];
        __block NSString *afilePath = [NSString pathWithComponents:@[saveZipPath, afileName]];
        
        [[INHttpClientUtil sharedInstance] downloadFileURL:curDownloadurl savePath:afilePath fileName:afilePath tag:[afilePath hash] downloadProgress:^(CGFloat progress) {
            
        } success:^(NSURLResponse *response, NSString *filePath) {
            //下载成功
            NSString *fileName = [[NSURL URLWithString:curDownloadurl] lastPathComponent];
            NSString *selFilePath = [NSString pathWithComponents:@[saveZipPath, fileName]];
            //准备执行解压方法
            [self onFileSelected:selFilePath unZipPath:themeUnZipPath];

        } failure:^(HttpError *e) {
            NSLog(@"failure request :%@",e);
        }];
    } else {
        //如果存在,直接显示
        __block NSString *saveZipPath = [self saveThemeTargetBasePath:themeModel.curVersion];
        __block NSString *themeUnZipPath = [self saveThemeDirBasePath:themeModel.curVersion];
        __block NSString *curDownloadurl = themeModel.curDownloadurl;
        //下载成功
        NSString *fileName = [[NSURL URLWithString:curDownloadurl] lastPathComponent];
        NSString *filePath = [NSString pathWithComponents:@[saveZipPath, fileName]];
        //准备执行解压方法
        [self unzipCompltion:themeUnZipPath];
    }

2.2 解压zip主题包

将下载的主题包解压,zip包进行解压。

objectivec 复制代码
// 解压
- (void)releaseZipFilesWithUnzipFileAtPath:(NSString *)zipPath destination:(NSString *)unzipPath {
    NSError *error;
    // 如果解压成功
    if ([SSZipArchive unzipFileAtPath:zipPath toDestination:unzipPath overwrite:YES password:nil error:&error delegate:self]) {
        // 存储主题的色调
        [self unzipCompltion:unzipPath];
    } else {
        NSLog(@"%@",error);
    }
}

解压完成后得到解压的目录。

2.3 获取到解压的目录地址,将配置的json文件转成对应的model

获取到解压的目录地址,将配置的json文件转成对应的model

objectivec 复制代码
/**
 调用解压文件
 
 @param unzipPath 获取地址
 */
- (void)unzipCompltion:(NSString *)unzipPath {
    // 存储主题的色调
    // 已经存储主题tabbar图片、navigationbar图片、配置文件等等资源
    
    NSArray *folders = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:unzipPath error:NULL];
    NSString *selectedFilePath = unzipPath;
    NSString *aPath = [folders lastObject];
    NSString *fullPath = [unzipPath stringByAppendingPathComponent:aPath];
    selectedFilePath = fullPath;
    
    NSString *configPath = [NSString stringWithFormat:@"%@/config.json",selectedFilePath];
    NSFileHandle *fh = [NSFileHandle fileHandleForReadingAtPath:configPath];
    NSData *data = [fh readDataToEndOfFile];
    NSString *jsonStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    
    NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithDictionary:[SDJsonUtil dictionaryWithJsonString:jsonStr]];
    NSLog(@"theme config.json:%@",dict);
    SDAppThemeConfigViewModel *themeViewModel = [SDAppThemeConfigViewModel themeViewModel:jsonStr];
    themeViewModel.t_globalImage = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.globalImage];
    
    themeViewModel.navigation.t_backgroundImage = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.navigation.backgroundImage];
    
    themeViewModel.tabbar.t_backgroundImage = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.tabbar.backgroundImage];
    
    themeViewModel.tabbar.lianlian.t_icon = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.tabbar.lianlian.icon];
    
    themeViewModel.tabbar.lianlian.t_selectedIcon = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.tabbar.lianlian.selectedIcon];
    
    themeViewModel.tabbar.guangguang.t_icon = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.tabbar.guangguang.icon];
    
    themeViewModel.tabbar.guangguang.t_selectedIcon = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.tabbar.guangguang.selectedIcon];
    
    themeViewModel.tabbar.message.t_icon = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.tabbar.message.icon];
    
    themeViewModel.tabbar.message.t_selectedIcon = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.tabbar.message.selectedIcon];
    
    themeViewModel.tabbar.mine.t_icon = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.tabbar.mine.icon];
    
    themeViewModel.tabbar.mine.t_selectedIcon = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.tabbar.mine.selectedIcon];
    
    //配置全局主题
    [SDAppThemeManager shareInstance].configViewModel = themeViewModel;
    
    [[NSNotificationCenter defaultCenter] postNotificationName:K_APP_THEME_CHANGED object:nil userInfo:nil];
}

之后通知界面切换对应的图片及风格图。

2.4 界面添加通知Observer

界面接收到通知后,更新到对应的图片及颜色。

我这里是就写一个切换Tabbar新年主题风格图片。

objectivec 复制代码
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(systemAppThemeChanged:) name:K_APP_THEME_CHANGED object:nil];

切换Tabbar新年主题风格图片

objectivec 复制代码
- (void)updateThemeConfig {
    //主题,可以更改tabbar样式
    SDAppThemeConfigViewModel *themeConfigViewModel = [SDAppThemeManager shareInstance].configViewModel;
    
    UIImage *backgroundImage;
    if (themeConfigViewModel.tabbar.t_backgroundImage) {
        backgroundImage = themeConfigViewModel.tabbar.t_backgroundImage;
    } else {
        NSString *bgColor = themeConfigViewModel.tabbar.backgroundColor;
        backgroundImage = [UIImage imageWithColor:[UIColor colorWithHexString:bgColor] size:CGSizeMake(20.0, 20.0)];
        backgroundImage = [backgroundImage stretchableImageWithLeftCapWidth:backgroundImage.leftCapWidth*0.5 topCapHeight:backgroundImage.topCapHeight*0.5];
    }
    
    self.sdTabbar.bgroundImage = backgroundImage;
    
    NSString *showLine = themeConfigViewModel.tabbar.showLine;
    self.sdTabbar.showLine = [showLine boolValue];
    self.sdTabbar.lineColor = [UIColor colorWithHexString:themeConfigViewModel.tabbar.lineColor];
    
    UIColor *badgeBGColor = [UIColor colorWithHexString:themeConfigViewModel.tabbar.badgeBgColor];

    SDTabbarItem *homeItem = [self themeTabbarItem:themeConfigViewModel.tabbar.lianlian];
    homeItem.identifier = @"home";
    homeItem.badgeColor = badgeBGColor;
    
    SDTabbarItem *addressbookItem = [self themeTabbarItem:themeConfigViewModel.tabbar.message];
    addressbookItem.identifier = @"addressbook";
    addressbookItem.badgeColor = badgeBGColor;

    SDTabbarItem *discoveryItem = [self themeTabbarItem:themeConfigViewModel.tabbar.guangguang];
    discoveryItem.identifier = @"discovery";
    discoveryItem.badgeColor = badgeBGColor;

    SDTabbarItem *mineItem = [self themeTabbarItem:themeConfigViewModel.tabbar.mine];
    mineItem.identifier = @"mine";
    mineItem.badgeColor = badgeBGColor;

    [self.sdTabbar updateTabbarStyle:homeItem];
    [self.sdTabbar updateTabbarStyle:addressbookItem];
    [self.sdTabbar updateTabbarStyle:discoveryItem];
    [self.sdTabbar updateTabbarStyle:mineItem];
}

- (void)systemAppThemeChanged:(NSNotification *)notification {
    [self updateThemeConfig];
}

- (SDTabbarItem *)themeTabbarItem:(SDAppThemeConfigTabItemViewModel *)itemViewModel {
    SDTabbarItem *tabbarItem = [[SDTabbarItem alloc] init];
    tabbarItem.title = itemViewModel.title;
    tabbarItem.titleColor = [UIColor colorWithHexString:itemViewModel.titleColor];
    tabbarItem.selectedTitleColor = [UIColor colorWithHexString:itemViewModel.selectedTitleColor];
    tabbarItem.image = itemViewModel.t_icon;
    tabbarItem.selectedImage = itemViewModel.t_selectedIcon;
    return tabbarItem;
}

tabbar的按钮更新:根据对应的identifier切换到对应的图片及颜色配置。

objectivec 复制代码
/**
 更新tabbar样式
 
 @param tabbarItem item
 */
- (void)updateTabbarStyle:(SDTabbarItem *)tabbarItem {
    for (UIView *subView in self.subviews) {
        if ([subView isKindOfClass:[SDTabbarButton class]]) {
            SDTabbarButton *tabbarButton = (SDTabbarButton *)subView;
            SDTabbarItem *item = tabbarButton.tabbarItem;
            if (tabbarItem.identifier && [tabbarItem.identifier isEqualToString:item.identifier]) {
                //更新tabbar
                [item copyClone:tabbarItem];
                tabbarButton.tabbarItem = item;
                break;
            }
        }
    }
}

三、将model序列化存储到本地目录

将主题数据序列号存储到本地目录,方便下次打开APP进行获取。

SDAppThemeConfigDbManager.h

objectivec 复制代码
#import <Foundation/Foundation.h>
#import "SDAppThemeManager.h"

@interface SDAppThemeConfigDbManager : NSObject

+ (id)shareInstance;

- (SDAppThemeViewModel *)getAppThemeViewModelFromDb;

- (void)saveAppThemeViewModelToDb:(SDAppThemeViewModel *)info;

@end

SDAppThemeConfigDbManager.m

objectivec 复制代码
#import "SDAppThemeConfigDbManager.h"

static NSString *appThemeConfigPath = @"sdAppThemeConfigPath";
static SDAppThemeConfigDbManager *instance = nil;

@implementation SDAppThemeConfigDbManager

+ (id)shareInstance
{
    static dispatch_once_t predicate;
    dispatch_once(&predicate,^{
        instance = [[self alloc] init];
    });
    return instance;
}

- (NSString *)getAppThemeConfigPath
{
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentPath = [paths objectAtIndex:0];
    NSString *path = [documentPath stringByAppendingPathComponent:appThemeConfigPath];
    
    return path;
}

- (SDAppThemeViewModel *)getAppThemeViewModelFromDb {
    NSString *dataFile = [self getAppThemeConfigPath];
    @try {
        SDAppThemeViewModel *viewModel = [NSKeyedUnarchiver unarchiveObjectWithFile:dataFile];
        if (viewModel) {
            return viewModel;
        }
    } @catch (NSException *e) {
        
    }
    
    return nil;
}

- (void)saveAppThemeViewModelToDb:(SDAppThemeViewModel *)info {
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:info];
    NSString *dataFile = [self getAppThemeConfigPath];
    
    BOOL isSave = [data writeToFile:dataFile atomically:YES];
    if (isSave) {
        NSLog(@"存储成功");
    } else {
        NSLog(@"存储失败");
    }
}

@end

四、完整实现代码

  • 需要用到主题Manager:SDAppThemeManager

SDAppThemeManager.h

objectivec 复制代码
#import <Foundation/Foundation.h>
//#import "SDThemeConfigRequest.h"
#import "SDAppThemeConfigViewModel.h"

/**
 获取的app主题model,app主题颜色版本号
 */
@interface SDAppThemeViewModel : NSObject<NSCoding>

@property (nonatomic, strong) NSString *curDownloadurl;     //当前版本的下载地址
@property (nonatomic, strong) NSString *curVersion;         //当前app主题颜色版本号

@property (nonatomic, strong) NSString *nextDownloadurl;    //下一版本的下载地址
@property (nonatomic, strong) NSString *nextVersion;        //下一版本app主题颜色版本号

@end

@interface SDAppThemeManager : NSObject

+ (instancetype)shareInstance;

@property (nonatomic, strong) SDAppThemeConfigViewModel *configViewModel; //当前版本控制文件

/**
 从服务器端加载APP主题接口
 */
- (void)loadAppThemeConfig;

/**
 加载系统主题资源
 */
- (void)loadCacheThemeResource;

@end

SDAppThemeManager.m

objectivec 复制代码
#import "SDAppThemeManager.h"
#import "SDAppThemeConfigDbManager.h"
#import "SDAppThemeDownloadManager.h"
#import "INHttpClientUtil.h"

@implementation SDAppThemeViewModel

- (id)init {
    self = [super init];
    if (self) {
        
    }
    return self;
}

- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super init];
    if (self) {
        self.curDownloadurl = [aDecoder decodeObjectForKey:@"kAppThemeCurDownloadurl"];
        self.curVersion = [aDecoder decodeObjectForKey:@"kAppThemeCurVersion"];
        self.nextDownloadurl = [aDecoder decodeObjectForKey:@"kAppThemeNextDownloadurl"];
        self.nextVersion = [aDecoder decodeObjectForKey:@"kAppThemeNextVersion"];
    }
    return self;
}

- (void)encodeWithCoder:(NSCoder *)aCoder
{
    [aCoder encodeObject:_curDownloadurl forKey:@"kAppThemeCurDownloadurl"];
    [aCoder encodeObject:_curVersion forKey:@"kAppThemeCurVersion"];
    [aCoder encodeObject:_nextDownloadurl forKey:@"kAppThemeNextDownloadurl"];
    [aCoder encodeObject:_nextVersion forKey:@"kAppThemeNextVersion"];
}

- (void)clear {
    self.curDownloadurl = nil;
    self.curVersion = nil;
    self.nextDownloadurl = nil;
    self.nextVersion = nil;
}


@end

static SDAppThemeManager *shareInstance = nil;

@implementation SDAppThemeManager

+ (instancetype)shareInstance {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        shareInstance = [[SDAppThemeManager alloc] init];
        shareInstance.configViewModel = [SDAppThemeConfigViewModel defautThemeViewModel];
    });
    return shareInstance;
}

/**
 从服务器端加载APP主题接口
 */
- (void)loadAppThemeConfig {
    [[INHttpClientUtil sharedInstance] getWithClientType:HttpClientTypeDefault url:@"/v1/api/theme/system" params:nil success:^(id responseObj) {
        NSString *code = [NSString stringWithFormat:@"%@",responseObj[@"code"]];
        if ([@"0" isEqualToString:code] && responseObj[@"data"]) {
            NSString *curDownloadurl = responseObj[@"data"][@"curDownloadurl"];
            NSString *curVersion = responseObj[@"data"][@"curVersion"];
            NSString *nextDownloadurl = responseObj[@"data"][@"nextDownloadurl"];
            NSString *nextVersion = responseObj[@"data"][@"nextVersion"];
            
            SDAppThemeViewModel *themeViewModel = [[SDAppThemeViewModel alloc] init];
            themeViewModel.curDownloadurl = nextDownloadurl;
            themeViewModel.curVersion = @"2016.10.27";
            themeViewModel.nextDownloadurl = nextDownloadurl;
            themeViewModel.nextVersion = nextVersion;
            
            [[SDAppThemeConfigDbManager shareInstance] saveAppThemeViewModelToDb:themeViewModel];
            
            [[SDAppThemeDownloadManager shareInstance] downloadThemeZipPackage:themeViewModel];
        }
    } failure:^(HttpError *e) {
        DLog(@"request:%@",e);
    }];
}

/**
 加载系统主题资源
 */
- (void)loadCacheThemeResource {
    [[SDAppThemeDownloadManager shareInstance] loadCacheThemeResource];
}

@end
  • 需要用到主题下载类SDAppThemeDownloadManager

SDAppThemeDownloadManager.h

objectivec 复制代码
#import <Foundation/Foundation.h>
//#import "SDThemeConfigRequest.h"
#import "SDAppThemeManager.h"
#import "SDAppThemeConfigViewModel.h"
#import "SDAppThemeConfigDbManager.h"

#define K_APP_THEME_CHANGED @"K_APP_THEME_CHANGED"
#define K_DEFAULT_APP_THEME_VERSION @"1.0.0"

@interface SDAppThemeDownloadManager : NSObject

+ (instancetype)shareInstance;

- (void)downloadThemeZipPackage:(SDAppThemeViewModel *)themeModel;

/**
 加载系统主题资源
 */
- (void)loadCacheThemeResource;

@end

SDAppThemeDownloadManager.m

objectivec 复制代码
#import "SDAppThemeDownloadManager.h"
#import "SDJsonUtil.h"
//#import "NSString+ext.h"
#import <SSZipArchive/SSZipArchive.h>
#import "SDAppThemeManager.h"
#import "INHttpClientUtil.h"

static SDAppThemeDownloadManager *manager = nil;

@interface SDAppThemeDownloadManager () <SSZipArchiveDelegate>

@end

@implementation SDAppThemeDownloadManager

+ (instancetype)shareInstance {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [[SDAppThemeDownloadManager alloc] init];
    });
    return manager;
}

- (void)downloadThemeZipPackage:(SDAppThemeViewModel *)themeModel {
    
    //判断当前主题版本号下是否存在资源文件夹
    BOOL curThemeExist = [self hasAppThemeVersion:themeModel.curVersion];
    if (!curThemeExist) {
        //如果不存在,重新下载解压
        __block NSString *saveZipPath = [self saveThemeTargetBasePath:themeModel.curVersion];
        __block NSString *themeUnZipPath = [self saveThemeDirBasePath:themeModel.curVersion];
        __block NSString *curDownloadurl = themeModel.curDownloadurl;
        //下载成功
        NSString *afileName = [[NSURL URLWithString:curDownloadurl] lastPathComponent];
        __block NSString *afilePath = [NSString pathWithComponents:@[saveZipPath, afileName]];
        
        [[INHttpClientUtil sharedInstance] downloadFileURL:curDownloadurl savePath:afilePath fileName:afilePath tag:[afilePath hash] downloadProgress:^(CGFloat progress) {
            
        } success:^(NSURLResponse *response, NSString *filePath) {
            //下载成功
            NSString *fileName = [[NSURL URLWithString:curDownloadurl] lastPathComponent];
            NSString *selFilePath = [NSString pathWithComponents:@[saveZipPath, fileName]];
            //准备执行解压方法
            [self onFileSelected:selFilePath unZipPath:themeUnZipPath];

        } failure:^(HttpError *e) {
            NSLog(@"failure request :%@",e);
        }];
    } else {
        //如果存在,直接显示
        __block NSString *saveZipPath = [self saveThemeTargetBasePath:themeModel.curVersion];
        __block NSString *themeUnZipPath = [self saveThemeDirBasePath:themeModel.curVersion];
        __block NSString *curDownloadurl = themeModel.curDownloadurl;
        //下载成功
        NSString *fileName = [[NSURL URLWithString:curDownloadurl] lastPathComponent];
        NSString *filePath = [NSString pathWithComponents:@[saveZipPath, fileName]];
        //准备执行解压方法
        [self unzipCompltion:themeUnZipPath];
    }
    
    /*
     //判断下一主题版本号下是否存在资源文件夹中
     BOOL nextThemeExist = [self hasAppThemeVersion:themeModel.nextVersion];
     if (!nextThemeExist) {
     //如果不存在,重新下载解压
     __block NSString *saveZipPath = [self saveThemeTargetBasePath:themeModel.nextVersion];
     [[HttpClient sharedInstance] downloadFileURL:themeModel.curDownloadurl savePath:saveZipPath fileName:saveZipPath tag:[saveZipPath hash] success:^(id responseObj) {
     //下载成功
     } failure:^(HttpException *e) {
     //下载失败
     }];
     }
     */
}

// 解压
- (void)releaseZipFilesWithUnzipFileAtPath:(NSString *)zipPath destination:(NSString *)unzipPath {
    NSError *error;
    // 如果解压成功
    if ([SSZipArchive unzipFileAtPath:zipPath toDestination:unzipPath overwrite:YES password:nil error:&error delegate:self]) {
        // 存储主题的色调
        [self unzipCompltion:unzipPath];
    } else {
        NSLog(@"%@",error);
    }
}

/**
 调用解压文件
 
 @param unzipPath 获取地址
 */
- (void)unzipCompltion:(NSString *)unzipPath {
    // 存储主题的色调
    // 已经存储主题tabbar图片、navigationbar图片、配置文件等等资源
    
    NSArray *folders = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:unzipPath error:NULL];
    NSString *selectedFilePath = unzipPath;
    NSString *aPath = [folders lastObject];
    NSString *fullPath = [unzipPath stringByAppendingPathComponent:aPath];
    selectedFilePath = fullPath;
    
    NSString *configPath = [NSString stringWithFormat:@"%@/config.json",selectedFilePath];
    NSFileHandle *fh = [NSFileHandle fileHandleForReadingAtPath:configPath];
    NSData *data = [fh readDataToEndOfFile];
    NSString *jsonStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    
    NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithDictionary:[SDJsonUtil dictionaryWithJsonString:jsonStr]];
    NSLog(@"theme config.json:%@",dict);
    SDAppThemeConfigViewModel *themeViewModel = [SDAppThemeConfigViewModel themeViewModel:jsonStr];
    themeViewModel.t_globalImage = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.globalImage];
    
    themeViewModel.navigation.t_backgroundImage = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.navigation.backgroundImage];
    
    themeViewModel.tabbar.t_backgroundImage = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.tabbar.backgroundImage];
    
    themeViewModel.tabbar.lianlian.t_icon = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.tabbar.lianlian.icon];
    
    themeViewModel.tabbar.lianlian.t_selectedIcon = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.tabbar.lianlian.selectedIcon];
    
    themeViewModel.tabbar.guangguang.t_icon = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.tabbar.guangguang.icon];
    
    themeViewModel.tabbar.guangguang.t_selectedIcon = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.tabbar.guangguang.selectedIcon];
    
    themeViewModel.tabbar.message.t_icon = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.tabbar.message.icon];
    
    themeViewModel.tabbar.message.t_selectedIcon = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.tabbar.message.selectedIcon];
    
    themeViewModel.tabbar.mine.t_icon = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.tabbar.mine.icon];
    
    themeViewModel.tabbar.mine.t_selectedIcon = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.tabbar.mine.selectedIcon];
    
    //配置全局主题
    [SDAppThemeManager shareInstance].configViewModel = themeViewModel;
    
    [[NSNotificationCenter defaultCenter] postNotificationName:K_APP_THEME_CHANGED object:nil userInfo:nil];
}

/**
 准备执行解压方法
 
 @param selectedPath 原先文件路径
 @param unZipPath 解压文件路径
 */
- (void)onFileSelected:(NSString *)selectedPath unZipPath:(NSString *)unZipPath {
    NSURL *fileURL = [NSURL fileURLWithPath:selectedPath];
    
    NSString *fileNameComponent = fileURL.lastPathComponent;
    // 获取文件的扩展名
    NSString *extension = [[fileNameComponent pathExtension] lowercaseString];
    // 如果是zip类型的压缩包文件,则进行解压
    if ([extension isEqualToString:@"zip"]) {
        // 设置解压路径
        [self releaseZipFilesWithUnzipFileAtPath:selectedPath destination:unZipPath];
    }
}

/**
 判断当前path路径是否存在
 
 @param themeVersion 主题版本号
 @return 是否文件
 */
- (BOOL)hasAppThemeVersion:(NSString *)themeVersion {
    NSString *pathOfLibrary = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
    NSString *path = [pathOfLibrary stringByAppendingPathComponent:[NSString stringWithFormat:@"dftheme-%@",themeVersion]];
    
    NSArray *folders = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:NULL];
    
    if (!(folders && folders.count > 0)) {
        return NO;
    }
    
    NSString *aPath = [folders lastObject];
    NSString *fullPath = [path stringByAppendingPathComponent:aPath];
    
    NSFileManager *fileManager = [NSFileManager defaultManager];
    BOOL result = [fileManager fileExistsAtPath:fullPath];
    
    return result;
}

/**
 主题未解压下载目录
 
 @param themeVersion 主题版本号
 @return 最后path
 */
- (NSString *)saveThemeTargetBasePath:(NSString *)themeVersion {
    NSString *pathOfLibrary = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
    NSString *path = [pathOfLibrary stringByAppendingPathComponent:[NSString stringWithFormat:@"dfThemesZip-%@",themeVersion]];
    [self createDirectory:path];
    return path;
}

/**
 主题解压目录
 
 @param themeVersion 主题版本号
 @return 最后path
 */
- (NSString *)saveThemeDirBasePath:(NSString *)themeVersion {
    NSString *pathOfLibrary = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
    NSString *path = [pathOfLibrary stringByAppendingPathComponent:[NSString stringWithFormat:@"dftheme-%@",themeVersion]];
    [self createDirectory:path];
    return path;
}

- (void)createDirectory:(NSString *)path {
    NSError *error = nil;
    [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES
                                               attributes:nil error:&error];
    if (error) {
        NSLog(@"Create directory error: %@", error);
    }
}

/**
 获取使用存储在沙盒里的图片
 
 @param documentoryName 文件目录
 @param imageName 图片名字
 @return 图片
 */
- (UIImage *)imageWithDocumentoryName:(NSString *)documentoryName
                            imageName:(NSString *)imageName {
    
    // 如果文件名不存在或者文件名为空,则返回空
    if (!imageName || [imageName isEqualToString:@""]) {
        return nil;
    }
    
    NSString *imgPath = [documentoryName stringByAppendingPathComponent:[NSString stringWithFormat:@"%@",imageName]];
    
    UIImage *image = [UIImage imageWithContentsOfFile:imgPath];
    
    if (image) {
        return image;
    }
    
    return [UIImage imageNamed:imageName];
}

/**
 加载系统主题资源
 */
- (void)loadCacheThemeResource {
    SDAppThemeViewModel *themeVersionViewModel = [[SDAppThemeConfigDbManager shareInstance] getAppThemeViewModelFromDb];
    if (themeVersionViewModel && ![K_DEFAULT_APP_THEME_VERSION isEqualToString:themeVersionViewModel.curVersion]) {
        [self downloadThemeZipPackage:themeVersionViewModel];
    }
}

@end

  • 需要用到主题数据:SDAppThemeConfigViewModel

SDAppThemeConfigViewModel.h

objectivec 复制代码
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

/**
 Navigation主题样式
 */
@interface SDAppThemeConfigNavViewModel : NSObject

@property (nonatomic, strong) NSString *backgroundColor;
@property (nonatomic, strong) NSString *backgroundImage;

@property (nonatomic, strong) UIImage *t_backgroundImage;

@property (nonatomic, strong) NSString *btnImageColor;
@property (nonatomic, strong) NSString *btnTitleColor;
@property (nonatomic, strong) NSString *navTitleColor;

@property (nonatomic, strong) NSString *showLine;
@property (nonatomic, strong) NSString *lineColor;

@end

/**
 单个tab按钮样式
 */
@interface SDAppThemeConfigTabItemViewModel : NSObject

@property (nonatomic, strong) NSString *title;
@property (nonatomic, strong) NSString *titleColor;
@property (nonatomic, strong) NSString *selectedTitleColor;
@property (nonatomic, strong) NSString *icon;
@property (nonatomic, strong) NSString *selectedIcon;

@property (nonatomic, strong) UIImage *t_icon;
@property (nonatomic, strong) UIImage *t_selectedIcon;

@end

/**
 tabbar样式
 */
@interface SDAppThemeConfigTabViewModel : NSObject

@property (nonatomic, strong) NSString *backgroundColor;
@property (nonatomic, strong) NSString *backgroundImage;
@property (nonatomic, strong) NSString *showLine;
@property (nonatomic, strong) NSString *lineColor;
@property (nonatomic, strong) NSString *badgeBgColor;

@property (nonatomic, strong) UIImage *t_backgroundImage;

@property (nonatomic, strong) SDAppThemeConfigTabItemViewModel *lianlian;
@property (nonatomic, strong) SDAppThemeConfigTabItemViewModel *guangguang;
@property (nonatomic, strong) SDAppThemeConfigTabItemViewModel *message;
@property (nonatomic, strong) SDAppThemeConfigTabItemViewModel *shop;
@property (nonatomic, strong) SDAppThemeConfigTabItemViewModel *mine;

@end

/**
 将本地的主题config.json转成viewmodel
 */
@interface SDAppThemeConfigViewModel : NSObject

@property (nonatomic, strong) NSString *globalColor;
@property (nonatomic, strong) NSString *globalImage;
@property (nonatomic, strong) SDAppThemeConfigNavViewModel *navigation;
@property (nonatomic, strong) SDAppThemeConfigTabViewModel *tabbar;

@property (nonatomic, strong) UIImage *t_globalImage;

+ (SDAppThemeConfigViewModel *)themeViewModel:(NSString *)themeJson;

+ (SDAppThemeConfigViewModel *)defautThemeViewModel;

@end

SDAppThemeConfigViewModel.m

objectivec 复制代码
#import "SDAppThemeConfigViewModel.h"
#import <NSObject+YYModel.h>

/**
 Navigation主题样式
 */
@implementation SDAppThemeConfigNavViewModel

@end

/**
 单个tab按钮样式
 */
@implementation SDAppThemeConfigTabItemViewModel

@end

/**
 tabbar样式
 */
@implementation SDAppThemeConfigTabViewModel

@end

/**
 将本地的主题config.json转成viewmodel
 */
@implementation SDAppThemeConfigViewModel

+ (SDAppThemeConfigViewModel *)themeViewModel:(NSString *)themeJson {
    return [SDAppThemeConfigViewModel modelWithJSON:themeJson];
}

+ (SDAppThemeConfigViewModel *)defautThemeViewModel {
    SDAppThemeConfigViewModel *viewModel = [[SDAppThemeConfigViewModel alloc] init];
    SDAppThemeConfigNavViewModel *navConfigViewModel = [[SDAppThemeConfigNavViewModel alloc] init];
    navConfigViewModel.backgroundColor = @"171013";
    navConfigViewModel.btnImageColor = @"ffffff";
    navConfigViewModel.btnTitleColor = @"ffffff";
    navConfigViewModel.navTitleColor = @"ffffff";
    viewModel.navigation = navConfigViewModel;
    return viewModel;
}

@end
  • 主题配置序列化存储本地:SDAppThemeConfigDbManager

SDAppThemeConfigDbManager.h

objectivec 复制代码
#import <Foundation/Foundation.h>
#import "SDAppThemeManager.h"

@interface SDAppThemeConfigDbManager : NSObject

+ (id)shareInstance;

- (SDAppThemeViewModel *)getAppThemeViewModelFromDb;

- (void)saveAppThemeViewModelToDb:(SDAppThemeViewModel *)info;

@end

SDAppThemeConfigDbManager.m

objectivec 复制代码
#import "SDAppThemeConfigDbManager.h"

static NSString *appThemeConfigPath = @"sdAppThemeConfigPath";
static SDAppThemeConfigDbManager *instance = nil;

@implementation SDAppThemeConfigDbManager

+ (id)shareInstance
{
    static dispatch_once_t predicate;
    dispatch_once(&predicate,^{
        instance = [[self alloc] init];
    });
    return instance;
}

- (NSString *)getAppThemeConfigPath
{
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentPath = [paths objectAtIndex:0];
    NSString *path = [documentPath stringByAppendingPathComponent:appThemeConfigPath];
    
    return path;
}

- (SDAppThemeViewModel *)getAppThemeViewModelFromDb {
    NSString *dataFile = [self getAppThemeConfigPath];
    @try {
        SDAppThemeViewModel *viewModel = [NSKeyedUnarchiver unarchiveObjectWithFile:dataFile];
        if (viewModel) {
            return viewModel;
        }
    } @catch (NSException *e) {
        
    }
    
    return nil;
}

- (void)saveAppThemeViewModelToDb:(SDAppThemeViewModel *)info {
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:info];
    NSString *dataFile = [self getAppThemeConfigPath];
    
    BOOL isSave = [data writeToFile:dataFile atomically:YES];
    if (isSave) {
        NSLog(@"存储成功");
    } else {
        NSLog(@"存储失败");
    }
}

@end

至此,实现获取下载主题配置更切换主题的代码实现完成。

五、小结

iOS开发-实现获取下载主题配置更切换主题,主要是通过请求服务端配置的主题配置、下载主题、解压保存到本地。通知界面获取对应的图片及颜色等。

学习记录,每天不停进步。

相关推荐
幽夜落雨3 分钟前
ios老版本应用安装方法
ios
gxhlh6 小时前
局域网中 Windows 与 Mac 互相远程连接的最佳方案
windows·macos
宏基骑士6 小时前
mac 电脑上安装adb命令
macos·adb
胖虎18 小时前
实现 iOS 自定义高斯模糊文字效果的 UILabel(文末有Demo)
ios·高斯模糊文字·模糊文字
水银嘻嘻13 小时前
【Mac】Python相关知识经验
开发语言·python·macos
梦魇梦狸º1 天前
mac 配置 python 环境变量
chrome·python·macos
丁总学Java1 天前
macOS如何进入 Application Support 目录(cd: string not in pwd: Application)
macos
qdprobot1 天前
Mixly米思齐1.0 2.0 3.0 软件windows版本MAC苹果电脑系统安装使用常见问题与解决
windows·macos
麦克Mapp1 天前
不用安装双系统,如何在mac上玩windows游戏呢?
macos
符小易1 天前
Mac苹果电脑 怎么用word文档和Excel表格?
macos·word·excel