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

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/51830.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【002 操作系统】进程的状态及状态转换图?

一、进程的状态 1. 创建状态 2. 就绪状态 3. 运行状态 4. 阻塞状态 5. 终止状态 图源&#xff1a;进程、线程基础知识全家桶&#xff0c;30 张图一套带走_Linux_小林coding_InfoQ写作社区 NULL -> 创建状态&#xff1a;一个新进程被创建时的第一个状态&#xff1b; 创建状态…

LT6911C 是一款HDMI 1.4到双端口MIPIDSI/CSI或者LVDS加音频的一款高性能芯片

LT6911C 1.描述&#xff1a; LT6911C是一款高性能的HDMI1.4到MIPIDSI/CSI/LVDS芯片&#xff0c;用于VR/智能手机/显示器应用程序。对于MIPIDSI/CSI输出&#xff0c;LT6911C具有可配置的单端口或双端口MIPIDSI/CSI&#xff0c;具有1个高速时钟通道和1个~4个高速数据通道&#…

nacos源码打包及相关配置

nacos 本地下载后&#xff0c;需要 install 下&#xff1a; mvn clean install -Dmaven.test.skiptrue -Dcheckstyle.skiptrue -Dpmd.skiptrue -Drat.skiptruenacos源码修改后&#xff0c;重新打包生成压缩包命令&#xff1a;在 distribution 目录中运行&#xff1a; mvn -Pr…

Java 源码打包 降低jar大小

这里写目录标题 Idea maven 插件配置pom.xml 配置启动技巧 Idea maven 插件配置 pom.xml 配置 <build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><!-- 只…

《吐血整理》进阶系列教程-拿捏Fiddler抓包教程(11)-Fiddler设置安卓手机抓包,不会可是万万不行的!

1.简介 Fiddler不但能截获各种浏览器发出的 HTTP 请求&#xff0c;也可以截获各种智能手机发出的HTTP/ HTTPS 请求。 Fiddler能截获 Android 和 Windows Phone 等设备发出的 HTTP/HTTPS 请求。 今天宏哥讲解和分享Fiddler 如何截获安卓移动端发出的 HTTP/HTTPS 请求。 2.环…

Python基于PyTorch实现卷积神经网络回归模型(CNN回归算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 卷积神经网络&#xff0c;简称为卷积网络&#xff0c;与普通神经网络的区别是它的卷积层内的神经元只覆…

抖音seo短视频矩阵系统源码开发解析---多账号授权管理

本文开发语音使用PHP语言开发&#xff0c;梅雨plum框架自主研发&#xff0c;文末另附开发技巧 抖音SEO短视频矩阵系统源码开发解析是一种基于抖音平台的短视频排名优化技术&#xff0c;通过对抖音算法的分析和抖音用户行为的研究&#xff0c;提供一种基于“流量矩阵”的短视频管…

通过STM32内部ADC将烟雾传感器发送的信号值显示在OLED上

一.CubeMX配置 首先我们在CubeMX配置ADC1, 设置一个定时器TIM2定时1s采样一次以及刷新一次OLED&#xff0c; 打开IIC用于驱动OLED显示屏。 二.程序 在Keil5中添加好oled的显示库&#xff0c;以及用来显示的函数、初始化函数、清屏函数等。在主程序中初始化oled,并将其清屏。…

二维深度卷积网络模型下的轴承故障诊断

1.数据集 使用凯斯西储大学轴承数据集&#xff0c;一共有4种负载下采集的数据&#xff0c;每种负载下有10种 故障状态&#xff1a;三种不同尺寸下的内圈故障、三种不同尺寸下的外圈故障、三种不同尺寸下的滚动体故障和一种正常状态 2.模型&#xff08;二维CNN&#xff09; 使…

现代C++中的从头开始深度学习:激活函数

一、说明 让我们通过在C中实现激活函数来获得乐趣。人工神经网络是生物启发模型的一个例子。在人工神经网络中&#xff0c;称为神经元的处理单元被分组在计算层中&#xff0c;通常用于执行模式识别任务。 在这个模型中&#xff0c;我们通常更喜欢控制每一层的输出以服从一些约束…

JVM入门篇-JVM的概念与学习路线

JVM入门篇-JVM的概念与学习路线 什么是 JVM 定义 Java Virtual Machine - java 程序的运行环境&#xff08;java 二进制字节码的运行环境&#xff09; 好处 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收功能数组下标越界检查多态 比较 jvm jre jdk 常…

C++语法(26)--- 特殊类设计

C语法&#xff08;25&#xff09;--- 异常与智能指针_哈里沃克的博客-CSDN博客https://blog.csdn.net/m0_63488627/article/details/131537799?spm1001.2014.3001.5501 目录 1.特殊类设计 1.设计一个类&#xff0c;不能被拷贝 C98 C11 2.设计一个类&#xff0c;只能在堆上…

Linux学成之路(基础篇0(二十三)MySQL服务(主从MySQL服务和读写分离——补充)

目录 一、MySQL Replication概述 优点 异步复制&#xff08;Asynchronous repication&#xff09; 全同步复制&#xff08;Fully synchronous replication&#xff09; 半同步复制&#xff08;Semisynchronous replication&#xff09; 三、MySQL支持的复制 四、部署主从…

真正帮你实现—MapReduce统计WordCount词频,并将统计结果按出现次数降序排列

项目整体介绍 对类似WordCount案例的词频统计&#xff0c;并将统计结果按出现次数降序排列。 网上有很多帖子&#xff0c;均用的相似方案&#xff0c;重写某某方法然后。。。运行起来可能会报这样那样的错误&#xff0c;这里实现了一种解决方案&#xff0c;分享出来供大家参考…

8年测试整理,自动化测试框架从0到1实施,一篇打通自动化...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 框架本身一般不完…

tauri在github上进行自动更新打包并发版过程,实战操作避坑

从网上找了很多很多的文章&#xff0c;结果还是入坑了&#xff0c;一个问题找了一天才解决&#xff1a; Error A public key has been found, but no private key. Make sure to set TAURI_PRIVATE_KEY environment variable. 596 ELIFECYCLE  Command failed with exit code…

NLP实验案例100个(1-5)

实验一 array数组&#xff08;01&#xff09; 一、实验目的及要求 1.安装numpy环境&#xff0c;掌握基本的数组知识以及操作。 二、实验设备&#xff08;环境&#xff09;及要求 开发环境&#xff1a;jupyter notebook 开发语言以及相关的库&#xff1a;python开发语言、nu…

hive删除数据进行恢复

在实际开发或生产中&#xff0c;hive表如果被误删&#xff0c;如被truncate或是分区表的分区被误删了&#xff0c;只要在回收站的清空周期内&#xff0c;是可以恢复数据的&#xff0c;步骤如下&#xff1a; &#xff08;1&#xff09; 先找到被删除数据的存放目录&#xff0c;…

CF1833 A-E

A题 题目链接&#xff1a;https://codeforces.com/problemset/problem/1833/A 基本思路&#xff1a;for循环遍历字符串s&#xff0c;依次截取字符串s的子串str&#xff0c;并保存到集合中&#xff0c;最后输出集合内元素的数目即可 AC代码&#xff1a; #include <iostrea…

MD-MTSP:斑马优化算法ZOA求解多仓库多旅行商问题MATLAB(可更改数据集,旅行商的数量和起点)

一、斑马优化算法ZOA 斑马优化算法&#xff08;Zebra Optimization Algorithm&#xff0c;ZOA&#xff09;Eva Trojovsk等人于2022年提出&#xff0c;其模拟斑马的觅食和对捕食者攻击的防御行为。斑马优化算法&#xff08;Zebra Optimization Algorithm&#xff0c;ZOA&#x…