ios app 实现热更新(无需发新版本实现app添加新功能)


目前能够实现热更新的方法,总结起来有以下三种

1. 使用FaceBook 的开源框架 reactive native,使用js写原生的ios应用

ios app可以在运行时从服务器拉取最新的js文件到本地,然后执行,因为js是一门动态的

脚本语言,所以可以在运行时直接读取js文件执行,也因此能够实现ios的热更新


2. 使用lua 脚本。lua脚本如同js 一样,也能在动态时被。之前愤怒的小鸟使用

lua脚本做的一个插件 wax,可以实现使用lua写ios应用。热更新时,从服务器拉去lua脚本

然后动态的执行就可以了。遗憾的是 wax目前已经不更新了。


上面是网上现在能够搜到的热更新方法。

xcode 6 之后,苹果开放了 ios 的动态库编译权限。所谓的动态库,其实就是可以在运行时加载。

正好利用这一个特性,用来做ios的热更新。

1.

建立一个动态库,如图:


动态库包含需要使用的viewCOntroller,当然可以包含任何需要使用的自定义ui和逻辑。

动态库的入口是一个jkDylib的类。它的.h和.m文件分别如下:

//
//  JKDylib.h
//  JKDylb
//
//  Created by wangdan on 15/7/5.
//  Copyright (c) 2015年 wangdan. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface JKDylib : NSObject

-(void)showViewAfterVC:(id)fromVc inBundle:(NSBundle*)bundle;

@end

.m文件

//
//  JKDylib.m
//  JKDylb
//
//  Created by wangdan on 15/7/5.
//  Copyright (c) 2015年 wangdan. All rights reserved.
//

#import "JKDylib.h"
#import "JKViewController.h"

@implementation JKDylib

-(void)showViewAfterVC:(id)fromVc inBundle:(NSBundle*)bundle
{
    if (fromVc == nil ) {
        return;
    }
    
    JKViewController *vc = [[JKViewController alloc] init];
    UIViewController *preVc = (UIViewController *)fromVc;
    
    if (preVc.navigationController) {
        [preVc.navigationController pushViewController:vc animated:YES];
    }
    else {
        UINavigationController *navi = [[UINavigationController alloc] init];
        [navi pushViewController:vc animated:YES];
    }
    
}
@end

上述代码意图非常明显,

就是调用该动态库的时候

-(void)showViewAfterVC:(id)fromVc inBundle:(NSBundle*)bundle
在该函数中,创建一个viewController 然后使用mainBundler 的navigationController  push 新建的viewController,显示动态库的ui界面。

而动态库中的JKViewController 内容则可以根据需要随便定义。


2. 完成上述动态库的编译工作后,现在需要做的就是在主工程中,写一段加载该动态库的代码。

主工程目录如下:


在最重要的viewCotrooler里面,定义了加载动态库的方法:

//
//  ViewController.m
//  DylibTest
//
//  Created by wangdan on 15/7/5.
//  Copyright (c) 2015年 wangdan. All rights reserved.
//

#import "ViewController.h"
#import "AFNetWorking.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
    self.title = @"bundle test";
    
    AFHTTPRequestOperationManager *manager = [[AFHTTPRequestOperationManager alloc] init];
    manager.responseSerializer = [AFJSONResponseSerializer serializer];
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com"]];
    [manager HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) {
        NSLog(@"request success");
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        NSLog(@"request failure");
    }];
    
    
    
    UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(0, 100, 100, 50)];
    btn.backgroundColor = [UIColor blueColor];
    
    [btn addTarget:self
            action:@selector(btnHandler)
  forControlEvents:UIControlEventTouchUpInside];
    
    [self.view addSubview:btn];
    
    NSString *document = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    
    BOOL writeResult =
    [@"hellow" writeToFile:[NSString stringWithFormat:@"%@/%@",document,@"hello.plist"] atomically:YES encoding:NSUTF8StringEncoding error:nil];
    
    // Do any additional setup after loading the view, typically from a nib.
}


-(void)btnHandler
{
    
    //AFHTTPRequestOperationManager *manager = [[AFHTTPRequestOperationManager alloc] init];
    //manager.responseSerializer = [AFJSONResponseSerializer serializer];
   // NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com"]];
   // [manager HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) {
    //    NSLog(@"request success");
   // } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
      // NSLog(@"request failure");
    //}];
    
    NSString *documentDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    NSString *bundlePath = [NSString stringWithFormat:@"%@/%@",documentDirectory,@"JKDylb.framework"];
    
    if (![[NSFileManager defaultManager] fileExistsAtPath:bundlePath]) {
        NSLog(@"file not exist ,now  return");
        return;
    }
    NSBundle *bundle = [NSBundle bundleWithPath:bundlePath];
    
    if (!bundle || ![bundle load]) {
        NSLog(@"bundle load error");
    }
    
    Class loadClass = [bundle principalClass];
    if (!loadClass) {
        NSLog(@"get bundle class fail");
        return;
    }
    NSObject *bundleObj = [loadClass new];
    [bundleObj performSelector:@selector(showViewAfterVC:inBundle:) withObject:self withObject:bundle];
    
    NSString *framePath = [[NSBundle mainBundle] privateFrameworksPath];
    NSLog(@"framePath is %@",framePath);
    
    NSLog(@"file attri \n %@",bundle.localizations);
    
//    [bundleObj showViewAfterVC:self inBundle:bundle];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

viewController视图中有一个按钮,点击按钮后,从 document目录下面找到动态库(虽然此时document下并没有动态库),动态库的名称约定好味

JKDylib.framework

然后使用NSBundle 加载该动态库,具体见代码。

加载成功后,调用在动态库中实现的方法

 [bundleObj performSelector:@selector(showViewAfterVC:inBundle:) withObject:self withObject:bundle];
    
编译该工程,然后运行到手机上,然后退出该程序


3. 打开itunes 然后将动态库同步到刚才的测试工程目录下。


4.在此打开测试工程程序,点击button,则会发现能够进入在动态库中定义的ui界面了。


上面工程的参考代码 在 

http://download.csdn.net/detail/j_akill/8891881


关于动态更新的思考:


采用动态库方式实现热更新其实还是有一个问题,就是如何在主工程和动态库之间共享组建

比如网络组件以及其他等等第三方组件。

目前我没发现好方法,只能在动态库和主工程之间分别添加并且编译。




  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 20
    评论
### 回答1: 以下是一个用 Objective-C 实现的检测 App 版本的例子: ``` NSString *currentVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; NSString *appStoreURL = [NSString stringWithFormat:@"http://itunes.apple.com/lookup?id=%@", APP_ID]; // APP_ID是你的应用程序在App Store中的ID NSURL *url = [NSURL URLWithString:appStoreURL]; NSString *appData = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil]; NSDictionary *jsonData = [NSJSONSerialization JSONObjectWithData:[appData dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableContainers error:nil]; NSString *latestVersion = [[[jsonData objectForKey:@"results"] objectAtIndex:0] objectForKey:@"version"]; if (![latestVersion isEqualToString:currentVersion]) { // 弹出提醒用户升级的对话框 } ``` 如果你想检测是否有新版本,并且提醒用户升级,可以在上面的代码的最后加上相应的逻辑。 注意事项:这段代码中的 APP_ID 和 iTunes URL 都需要替换成你自己的。此外,为了避免网络请求阻塞主线程,你应该在后台线程中执行网络请求操作。 ### 回答2: iOS系统通过检测app版本可以帮助用户及时获取应用程序的最功能和修复的Bug,提高用户体验。一般而言,iOS检测app版本的例子可以通过以下几种方式实现: 1. 通过App Store的更新提示:用户可以通过打开App Store,点击右下角的“更新”选项,系统会自动检测已安装应用的版本并显示需要更新的应用程序。用户可以根据需要选择更新或手动更新应用。 2. 后台自动检测:在应用程序启动时,可以通过后台接口请求服务器,检测是否有新版本可供下载。服务器可以提供一个存储最新版本的版本号,应用程序在启动时获取当前版本号与服务器的版本号进行比较,如不一致则提示用户有新版本可用。 3. 弹窗提醒:应用程序可以设置一个弹窗提醒用户有新版本可供下载。当用户打开应用程序时,如果检测到有新版本,则弹窗提醒用户前往App Store下载更新。 4. 版本检测接口:应用程序可以与服务器建立连接,通过接口请求服务器获取最新版本信息。服务器返回最新版本号及版本更新内容,应用程序解析后展示在界面上,让用户自行进行更新。 以上是iOS检测app版本的一些例子,具体的实现方式可以根据开者的需求和业务场景进行选择和定制。 ### 回答3: iOS检测app版本的一个例子是通过比较当前安装的app版本与服务器上最app版本来判断是否需要更新。 这个过程可以分为以下几个步骤: 1. 首先,我们需要获取当前设备上安装的app的版本号。可以通过在代码中获取Info.plist文件中的CFBundleShortVersionString键对应的值来实现,该值表示了app的当前版本号。 2. 下一步是从服务器上获取最app版本号。一种常见的做法是,后台维护一个存储了最app版本号以及相关信息的接口。我们可以通过向这个接口送请求,获取服务器上存储的最app版本号。 3. 接着,我们将当前设备上的版本号与服务器上的最新版本号进行比较。可以将版本号转换为整数或浮点数,然后进行比较操作。如果设备上的版本号小于服务器上的最新版本号,则说明需要进行更新。 4. 最后,如果需要进行更新,我们可以向用户展示一个弹窗或者推送一个通知,告知他们有新版本可用,并提供下载连接或提示他们前往App Store进行更新。 此外,我们还可以在app启动时进行版本检测,以保障用户使用的是最的版本。在每次启动或者在用户打开特定页面时,我们可以异步送一个请求到服务器,检查最新版本号。如果有更新,我们可以选择直接跳转到更新页面或者提供提示给用户。 总之,通过比较当前设备上的版本号和服务器上的最新版本号,我们可以便捷地实现iOS检测app版本的功能,及时提醒用户更新并提供下载链接,以提供更好的用户体验和功能支持。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值