iOS-OC-APP熱更新,動態更新(仿QQ開啟或關閉某個功能)

來源:互聯網
上載者:User

標籤:

一.前言iOS開發更新APP我覺得是比較坑的就是審核時間比較長,審核比較嚴,對於剛入行的小夥伴來說,雷區比較多;所以熱更新是比較重要的;大家也許會發現我們常用的QQ現在下來也就一百多兆,但是用了幾個月後發現QQ在手機上佔有一個多G的記憶體,特別是手機記憶體比較小的小夥伴,這是因為你在使用過程中,有一些功能是你下載下來的;
二.建立Framework1.建立項目建立一個Cocoa Touch Framework項目,然後在這個項目裡面寫你的新的功能,比如我建立了一個控制器,在控制器裡面載入一張圖和一個label;
<span style="font-size:18px;">- (void)uiConfig{    self.title = @"這是功能2";        UIImageView *imageView = [[UIImageView alloc]init];    imageView.frame = CGRectMake(0, 0, ScreenWidth, ScreenHeight);    NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://img4.duitang.com/uploads/item/201405/31/20140531174207_hH5u4.thumb.700_0.jpeg"]];    imageView.image = [UIImage imageWithData:data];    [self.view addSubview:imageView];        UILabel *label = [[UILabel alloc]init];    label.backgroundColor = [UIColor clearColor];    label.frame = CGRectMake(0, (ScreenHeight - 100)/2, ScreenWidth, 100);    label.numberOfLines = 0;    label.text = @"這是功能2這是功能2這是功能2這是功能2這是功能2這是功能2這是功能2這是功能2這是功能2這是功能2這是功能2這是功能2這是功能2這是功能2這是功能2";    [self.view addSubview:label];}</span>
2.添加Aggregate在TARGETS裡面建立一個Aggregate

3.添加Run Script指令碼

4.指令碼源碼
<span style="font-size:18px;"># Sets the target folders and the final framework product.# 如果工程名稱和Framework的Target名稱不一樣的話,要自訂FMKNAME# 例如: FMK_NAME = "MyFramework"FMK_NAME=${PROJECT_NAME}# Install dir will be the final output to the framework.# The following line create it in the root folder of the current project.INSTALL_DIR=${SRCROOT}/Products/${FMK_NAME}.framework# Working dir will be deleted after the framework creation.WRK_DIR=buildDEVICE_DIR=${WRK_DIR}/Release-iphoneos/${FMK_NAME}.frameworkSIMULATOR_DIR=${WRK_DIR}/Release-iphonesimulator/${FMK_NAME}.framework# -configuration ${CONFIGURATION}# Clean and Building both architectures.xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphoneos clean buildxcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphonesimulator clean build# Cleaning the oldest.if [ -d "${INSTALL_DIR}" ]thenrm -rf "${INSTALL_DIR}"fimkdir -p "${INSTALL_DIR}"cp -R "${DEVICE_DIR}/" "${INSTALL_DIR}/"# Uses the Lipo Tool to merge both binary files (i386 + armv6/armv7) into one Universal final product.lipo -create "${DEVICE_DIR}/${FMK_NAME}" "${SIMULATOR_DIR}/${FMK_NAME}" -output "${INSTALL_DIR}/${FMK_NAME}"rm -r "${WRK_DIR}"open "${INSTALL_DIR}"</span>

5.運行打包運行工程,將產生的framework包壓縮zip,然後上傳伺服器;例如:http://7xqdun.com1.z0.glb.clouddn.com/FunctionZFJ1.framework.zip
三.建立項目在項目中我們主要是下載和讀取framework包;我們先要擷取功能列表,在此我在本地寫了一個功能列表,大家如果用得到可以將功能列表存放在伺服器上;1.建立功能列表資料我添加了四個功能模組,存在NSUserDefaults裡面;其中功能1和功能2有,其他的沒有;功能1是個NSObject,功能2直接是一個控制器;isopen:1表示開啟,0表示關閉;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    // Override point for customization after application launch.    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];    self.window.backgroundColor = [UIColor whiteColor];    [self.window makeKeyAndVisible];        //添加假的功能列表    NSArray *functionList = [USER_DEFAULT objectForKey:@"functionList"];    if(functionList==nil || functionList.count==0){        NSArray *titleArr  = @[@"功能1",@"功能2",@"功能3",@"功能4"];        NSArray *className = @[@"HotUpdateControl",@"ZFJViewController",@"",@""];        NSArray *classType = @[@"NSObject",@"UIViewController",@"",@""];        NSArray *downUrl   = @[                               @"http://7xqdun.com1.z0.glb.clouddn.com/HotMudel.framework.zip",                               @"http://7xqdun.com1.z0.glb.clouddn.com/FunctionZFJ1.framework.zip",                               @"",                               @""];        NSMutableArray *functionArr = [[NSMutableArray alloc]init];        for (int i = 0; i<titleArr.count; i++) {            NSMutableDictionary *dict = [[NSMutableDictionary alloc]init];            [dict setObject:titleArr[i] forKey:@"name"];            [dict setObject:className[i] forKey:@"classname"];            [dict setObject:classType[i] forKey:@"classtype"];            [dict setObject:@(i) forKey:@"mid"];            [dict setObject:@"0" forKey:@"isopen"];//0 未開啟  1開啟了            [dict setObject:downUrl[i] forKey:@"downurl"];            [functionArr addObject:dict];        }        [USER_DEFAULT setObject:functionArr forKey:@"functionList"];        [USER_DEFAULT synchronize];    }        DynamicViewController *dvc = [[DynamicViewController alloc]init];    UINavigationController *nvc = [[UINavigationController alloc]initWithRootViewController:dvc];    self.window.rootViewController = nvc;        return YES;}

2.展示功能列表在功能列表主要用於展示所有開啟過的功能,也就是isopen為1的所有功能;a.擷取本地所有開啟的資料,然後在tableview上顯示
- (void)getDataBase{    [self.dataArray removeAllObjects];    NSArray *functionList = [USER_DEFAULT objectForKey:@"functionList"];    for (NSDictionary *dict in functionList) {        NSInteger isopen = [dict[@"isopen"] integerValue];        if(isopen==1){            [self.dataArray addObject:dict];        }    }    [self.tableview reloadData];}

b.點擊對於的tableviewcell 的時候跳轉對應的framework讀取出來的方法注意,我將不同的framework存放在不同的檔案夾下,以mid作為區分;
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{    [tableView deselectRowAtIndexPath:indexPath animated:YES];    NSDictionary *dict = self.dataArray[indexPath.row];    //擷取framework的路徑名,我已mid區分    NSString *destinationPath = [NSHomeDirectory() stringByAppendingString:[NSString stringWithFormat:@"/Documents/FunctionZFJ%@",dict[@"mid"]]];    NSArray* arrFramework = [self getFilenamelistOfType:@"framework" fromDirPath:destinationPath];    NSString *bundlePath = [NSString stringWithFormat:@"%@/%@",destinationPath,[arrFramework lastObject]];    if (![[NSFileManager defaultManager] fileExistsAtPath:bundlePath]) {        NSLog(@"檔案不存在");        return;    }        NSBundle *bundle = [NSBundle bundleWithPath:bundlePath];    if (!bundle || ![bundle load]) {        NSLog(@"bundle載入出錯");    }        NSString *className = dict[@"classname"];    NSString *classtype = dict[@"classtype"];        Class loadClass = [bundle classNamed:className];    if (!loadClass) {        NSLog(@"擷取失敗");        return;    }        if([classtype isEqualToString:@"NSObject"]){        NSObject *bundleObj = [loadClass new];        NSArray *arrVc = [bundleObj performSelector:@selector(getVcs)];        TabController *tvc = [[TabController alloc]initwithVcArray:arrVc];        [self.navigationController pushViewController:tvc animated:YES];    }else if([classtype isEqualToString:@"UIViewController"]){        UIViewController *uvc = (UIViewController *)[loadClass new];        [self.navigationController pushViewController:uvc animated:YES];    }}

c.


3.更多功能在這裡我們可以開啟或者關閉某個功能;a.擷取所以功能,包括開啟或者關閉狀態的;然後在tableview上顯示;
<span style="font-size:18px;">#pragma mark - 擷取全部資料- (void)getDataBase{    [self.dataArray removeAllObjects];        NSArray *functionList = [USER_DEFAULT objectForKey:@"functionList"];    NSMutableArray *openYES = [[NSMutableArray alloc]init];    NSMutableArray *openNO = [[NSMutableArray alloc]init];    for (NSDictionary *dict in functionList) {        NSMutableDictionary *muDict = [[NSMutableDictionary alloc]initWithDictionary:dict];        NSInteger isopen = [muDict[@"isopen"] integerValue];        if(isopen==1){            //已經開啟的功能            [openYES addObject:muDict];        }else{            //沒有開啟的功能            [openNO addObject:muDict];        }    }        [self.dataArray addObject:openNO];    [self.dataArray addObject:openYES];        [self.tableview reloadData];}</span>

b.開啟功能開啟某個功能就是下載對應的framework,把下載下來的zip包進行解壓一下然後擷取到framework,接著刪除zip包,把framework放在對於的目錄下;最後改變本地列表功能的狀態;
<span style="font-size:18px;">#pragma mark - 開啟某個功能 先下載資料- (void)SSZipArchiveDataBaseWithDict:(NSMutableDictionary *)dict{    NSString *requestURL = dict[@"downurl"];    if(requestURL==nil || requestURL.length==0){        self.progresslabel.text = [NSString stringWithFormat:@"%@-沒有,不能開啟!",dict[@"name"]];        UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示" message:@"沒有,不能開啟" preferredStyle:UIAlertControllerStyleAlert];        UIAlertAction *sureBtn = [UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleDefault handler:nil];        [alertController addAction:sureBtn];        [self presentViewController:alertController animated:YES completion:nil];        return;    }    //下載儲存的路徑    NSString *savedPath = [NSHomeDirectory() stringByAppendingString:[NSString stringWithFormat:@"/Documents/FunctionZFJ%@.framework.zip",dict[@"mid"]]];    AFHTTPRequestSerializer *serializer = [AFHTTPRequestSerializer serializer];    NSMutableURLRequest *request = [serializer requestWithMethod:@"POST" URLString:requestURL parameters:nil error:nil];    AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc]initWithRequest:request];    [operation setOutputStream:[NSOutputStream outputStreamToFileAtPath:savedPath append:NO]];    [operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {        float progress = (float)totalBytesRead / totalBytesExpectedToRead;        self.progresslabel.text = [NSString stringWithFormat:@"%@下載進度:%.2f",dict[@"name"],progress];    }];    [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {        NSLog(@"下載成功");        NSString *destinationPath = [NSHomeDirectory() stringByAppendingString:[NSString stringWithFormat:@"/Documents/FunctionZFJ%@",dict[@"mid"]]];        //對下載下來的ZIP包進行解壓        BOOL isScu = [SSZipArchive unzipFileAtPath:savedPath toDestination:destinationPath];        if(isScu){            NSLog(@"解壓成功");            NSFileManager *fileMgr = [NSFileManager defaultManager];            BOOL bRet = [fileMgr fileExistsAtPath:savedPath];            if (bRet) {                [fileMgr removeItemAtPath:savedPath error:nil];//解壓成功後刪除壓縮包            }            [dict setValue:@"1" forKey:@"isopen"];            [self updataBaseWithDict:dict];//解壓成功後更新本地功能列表狀態        }else{            NSLog(@"解壓失敗 --- 開啟失敗");        }            } failure:^(AFHTTPRequestOperation *operation, NSError *error) {        NSLog(@"下載失敗 --- 開啟失敗");            }];    [operation start];}</span>
更新本機資料
<span style="font-size:18px;">#pragma mark - 更新本機資料- (void)updataBaseWithDict:(NSMutableDictionary *)dict{    NSInteger mid = [dict[@"mid"] integerValue];    NSMutableArray *functionList = [USER_DEFAULT objectForKey:@"functionList"];    NSMutableArray *dataArr = [[NSMutableArray alloc]initWithArray:functionList];    [dataArr replaceObjectAtIndex:mid withObject:dict];    [USER_DEFAULT setObject:dataArr forKey:@"functionList"];    BOOL isScu = [USER_DEFAULT synchronize];    if(isScu){        [self getDataBase];//重新擷取資料 更新列表        if(self.refreshData){            self.refreshData();        }    }else{        NSLog(@"c操作失敗");    }}</span>

c.關閉功能關閉某個功能,也就是刪除某個功能的framework,然後更改功能列表的狀態;
<span style="font-size:18px;">#pragma mark - 關閉某個功能- (void)delectFunctionZFJWithDict:(NSMutableDictionary *)dict{    NSFileManager *fileMgr = [NSFileManager defaultManager];    NSString *savedPath = [NSHomeDirectory() stringByAppendingString:[NSString stringWithFormat:@"/Documents/FunctionZFJ%@",dict[@"mid"]]];    BOOL bRet = [fileMgr fileExistsAtPath:savedPath];    if (bRet) {        NSError *err;        //關閉某個功能 就是刪除本地的framework  然後修改本地功能狀態        BOOL isScu = [fileMgr removeItemAtPath:savedPath error:&err];        if(isScu){            [dict setValue:@"0" forKey:@"isopen"];            [self updataBaseWithDict:dict];        }else{            NSLog(@"關閉失敗");        }    }else{        NSLog(@"關閉失敗");    }}</span>

d.

四.原始碼在這裡面有,兩個framework的原始碼,可項目的代碼;注意,如果有多個功能的framework,記住多個framework的命名在同一個功能裡面不能重複,不然調取失敗;連結: https://pan.baidu.com/s/1mieyk3I 密碼: mg4m
五.







iOS-OC-APP熱更新,動態更新(仿QQ開啟或關閉某個功能)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

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

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

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

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