iOS开发-实现获取下载主题配置动态切换主题
iOS开发-实现获取下载主题配置更切换主题,主要是通过请求服务端配置的主题配置、下载主题、解压保存到本地。通知界面获取对应的图片及颜色等。
比如新年主题风格,常见的背景显示红色氛围图片、tabbar显示新年风格的按钮样式、导航条显示红色样式等。
一、主题Json对应的model
这里使用JsonModel将主题转成model
model代码如下
SDAppThemeConfigViewModel.h
#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
#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网络通信类库。
下载代码:
#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 判断主题版本是否已经下载
在获取主题版本时候,需要判断主题是否存在,如果存在,则直接获取保存的地址。不存在,下载解压当前版本的主题包。
//判断当前主题版本号下是否存在资源文件夹
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包进行解压。
// 解压
- (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
/**
调用解压文件
@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新年主题风格图片。
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(systemAppThemeChanged:) name:K_APP_THEME_CHANGED object:nil];
切换Tabbar新年主题风格图片
- (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切换到对应的图片及颜色配置。
/**
更新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
#import <Foundation/Foundation.h>
#import "SDAppThemeManager.h"
@interface SDAppThemeConfigDbManager : NSObject
+ (id)shareInstance;
- (SDAppThemeViewModel *)getAppThemeViewModelFromDb;
- (void)saveAppThemeViewModelToDb:(SDAppThemeViewModel *)info;
@end
SDAppThemeConfigDbManager.m
#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
#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
#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
#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
#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
#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
#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
#import <Foundation/Foundation.h>
#import "SDAppThemeManager.h"
@interface SDAppThemeConfigDbManager : NSObject
+ (id)shareInstance;
- (SDAppThemeViewModel *)getAppThemeViewModelFromDb;
- (void)saveAppThemeViewModelToDb:(SDAppThemeViewModel *)info;
@end
SDAppThemeConfigDbManager.m
#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开发-实现获取下载主题配置更切换主题,主要是通过请求服务端配置的主题配置、下载主题、解压保存到本地。通知界面获取对应的图片及颜色等。
学习记录,每天不停进步。