版本更新提示搭建(一)邏輯交互

需求如下:

屏幕快照 2019-03-25 上午11.19.36.png

先說下使用場景和需求:
1)登錄時版本更新覆劈,用戶啟動app登錄或自動登錄時疚脐,發(fā)送請求需要帶本應(yīng)用的當(dāng)前版本號忙灼,服務(wù)返回的結(jié)果中包含版本更新信息杭攻,并且一般立刻彈出提示讓用戶選擇,我們會分為兩種猫态,一種是強制更新(左圖)一種是非強制更新庶溶。
2)在我的→設(shè)置→檢查更新 模塊中進(jìn)行版本的更新。

思路:

版本更新一般分為:強制更新和非強制性更新懂鸵。
強制更新的本質(zhì)是由服務(wù)器來判斷偏螺,需要拿當(dāng)前版本號(服務(wù)器數(shù)據(jù)庫中存儲的應(yīng)用版本號)和應(yīng)用發(fā)送的版本號相比較。

具體實現(xiàn)如下:

我們項目是組件式開發(fā)匆光,因此這部分功能的實現(xiàn)套像,我們放到了Launch模塊組件中。

先創(chuàng)建一個服務(wù)單例终息,其中包含(開啟第三方夺巩、登錄成功之后數(shù)據(jù)初始化贞让、Jpush、Bugly柳譬、WX喳张、UM、IQ美澳、RN销部、配置token相關(guān)信息、token刷新無效 則跳轉(zhuǎn)登錄)等相關(guān)服務(wù)制跟。

本篇文章只針對檢查版本更新做介紹舅桩。

在程序開始啟動的時候,增加如下代碼

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyWindow];
    [[SCLaunchService shareInstance]startSCServices:nil];
    [[SCLaunchService shareInstance] openThirdServices:launchOptions block:nil env:SC_Env_Type];
    [self showLaunchView];
    [[SCLaunchService shareInstance] checkAppVersion:nil];
    return YES;
}

其中:

 [[SCLaunchService shareInstance] checkAppVersion:nil];

這個功能就是程序一啟動就會檢查版本情況

#import <Foundation/Foundation.h>
#import "smartSDKHeader.h"
#import "SCEnvParameterConfig.h"

@interface SCLaunchService : NSObject


+ (instancetype)shareInstance;

/**
  開啟服務(wù)(登錄成功后數(shù)據(jù)初始化)
 */
- (void)startSCServices:(VOIDBLOCK)started;

/**
 開啟三方服務(wù)
 @param started started description
 */
- (void)openThirdServices:(NSDictionary *)launchOptions block:(VOIDBLOCK)started env:(KEnvType)envType;
@interface SCLaunchService ()<JPUSHRegisterDelegate,JoyRouteProtocol>
@end
@implementation SCLaunchService
//用于登錄頁面完成之后相關(guān)服務(wù)的開啟
-(void)routeParam:(NSDictionary *)param block:(JoyRouteBlock)block{
    if ([[param objectForKey:@"type"] isEqualToString:@"startSCServices"]) {
        [self startSCServices:^{
            block?block(param,nil):nil;
        }];
    }
}

//創(chuàng)建一個單例
static SCLaunchService *instance = nil;

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

+ (instancetype)allocWithZone:(struct _NSZone *)zone{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [super allocWithZone:zone];
    });
    return instance;
}

- (instancetype)init{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [super init];
    });
    return instance;
}

- (id)copyWithZone:(NSZone *)zone{
    return instance;
}

- (id)mutableCopyWithZone:(NSZone *)zone{
    return instance;
}

#pragma mark 開啟服務(wù)
- (void)startSCServices:(VOIDBLOCK)started{
    [self configTokenInfo];
    started?started():nil;
}

#pragma mark 開啟三方服務(wù)
- (void)openThirdServices:(NSDictionary *)launchOptions block:(VOIDBLOCK)started env:(KEnvType)envType{
    [[SCEnvParameterConfig shareInstance] config:envType];
    //    [LocalCfg config:ENVSTR];
    [[SCUser shareInstance]setCacheInfo];
    [self addJpushWith:launchOptions];
    [self startBuglyService];
    [self startWXService];
    [self startUMServices];
    [self startIQKeyBoard];
    [self startRNService];
    [[JoyRouter sharedInstance]configScheme:@"scbu"];
    started?started():nil;
}

#pragma mark 配置token相關(guān)信息
- (void)configTokenInfo{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshTokenInvalid) name:KTOKEN_REFRESH_FAILURED object:nil];
}

#pragma mark token刷新無效 則跳轉(zhuǎn)登錄
- (void)refreshTokenInvalid{
    [[SCBleService shareInstance] stopService];
    [[JoyRouter sharedInstance]routerModule:@"user" path:@"login" actionType:JoyRouteActionTypeSetNavRooter parameter:nil block:nil];
}

#pragma mark 極光推送
- (void)addJpushWith:(NSDictionary *)launchOptions{
#if __has_include("JPUSHService.h")
    JPUSHRegisterEntity * entity = [[JPUSHRegisterEntity alloc] init];
    UIUserNotificationSettings *settings = [UIUserNotificationSettings
                                            settingsForTypes:UIUserNotificationTypeBadge categories:nil];
    [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
    //    [UIApplication sharedApplication].applicationIconBadgeNumber = 0;
    entity.types = JPAuthorizationOptionAlert|JPAuthorizationOptionBadge|JPAuthorizationOptionSound;
    [JPUSHService registerForRemoteNotificationConfig:entity delegate:self];
    NSString *jpushKey = [SCEnvParameterConfig shareInstance].JPUSH_APPKEY;
    BOOL isEnvRelease = [SCEnvParameterConfig shareInstance].envType == KEnvTypeRelease;
    [JPUSHService setupWithOption:launchOptions appKey:jpushKey
                          channel:nil
                 apsForProduction:isEnvRelease
            advertisingIdentifier:nil];
    [JPUSHService registrationIDCompletionHandler:^(int resCode, NSString *registrationID) {
        NSUserDefaults *deaults = [NSUserDefaults standardUserDefaults];
        [deaults setObject:registrationID forKey:@"registrationID"];
        NSLog(@"resCode : %d,registrationID: %@",resCode,registrationID);
    }];
#else
#endif
}

#pragma mark bugly服務(wù)
- (void)startBuglyService{
    NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];
    [Bugly startWithAppId:[SCEnvParameterConfig shareInstance].BUGLY_APPID];
    BuglyConfig * config = [[BuglyConfig alloc] init];
    config.reportLogLevel = BuglyLogLevelWarn;
    config.version = version;
    [Bugly startWithAppId:[SCEnvParameterConfig shareInstance].BUGLY_APPID config:config];
}

#pragma mark 微信服務(wù)
- (void)startWXService{
#if __has_include("WXApi.h")
    [WXApi registerApp:[SCEnvParameterConfig shareInstance].WEIXIN_APPID];
#else
#endif
}

#pragma mark 開啟友盟服務(wù)
- (void)startUMServices{
    NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];
    [MobClick startWithConfigure:UMConfigInstance];
    [MobClick setAppVersion:version];
    NSDictionary *config = @{};
    [GLLogging setupWithConfiguration:config];
}

- (void)startIQKeyBoard{
    //默認(rèn)為NO
    IQKeyboardManager *manager = [IQKeyboardManager sharedManager]; // 獲取類庫的單例變量
    manager.enable = YES; // 控制整個功能是否啟用
    manager.shouldResignOnTouchOutside = YES;//控制點擊背景是否收起鍵盤
    //    manager.toolbarManageBehaviour = IQAutoToolbarBySubviews;   // 有多個輸入框時雨膨,可以通過點擊Toolbar 上的“前一個”“后一個”按鈕來實現(xiàn)移動到不同的輸入框
    manager.enableAutoToolbar = NO; // 控制是否顯示鍵盤上的工具條
    //    manager.shouldShowTextFieldPlaceholder = NO;  // 是否顯示占位文字
    //    manager.placeholderFont = [UIFont systemFontOfSize:17]; // 設(shè)置占位文字的字體
    manager.keyboardDistanceFromTextField = 10.0f;  //// 輸入框距離鍵盤的距離
}

#pragma mark jpush delegate
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(NSInteger))completionHandler {
#if __has_include("JPUSHService.h")
    // Required
    NSDictionary * userInfo = notification.request.content.userInfo;
    NSDictionary *data = [NSDictionary dictionaryWithJsonString:userInfo[@"data"]];
    if([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
        [JPUSHService handleRemoteNotification:userInfo];
    }
    if ([userInfo[@"msgType"] isEqualToString:@"BppPayCallbackMessage"]) {
        [[NSNotificationCenter defaultCenter] postNotificationName:@"PayBcak" object:self userInfo:@{@"orderId":data[@"orderId"],@"status":data[@"status"],@"payType":data[@"payType"]}];
        return;
    }
    if (@available(iOS 10.0, *)) {
        if([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]] && [userInfo[@"msgType"] isEqualToString:@"message_center_detail"]) {
            NSDictionary *aps = [userInfo objectForKey:@"aps"];
            NSString *title = nil;
            if ([aps isKindOfClass:NSDictionary.class]){
                title = [aps objectForKey:@"alert"];
            }
            /// iOS10處理遠(yuǎn)程推送
            [JPUSHService handleRemoteNotification:userInfo];
            /// 應(yīng)用處于前臺收到推送的時候轉(zhuǎn)成本地通知 ===========================
            UILocalNotification *notification = [[UILocalNotification alloc] init];
            notification.alertBody =title?:@"告警通知";
            notification.userInfo = userInfo;
            [[UIApplication sharedApplication] presentLocalNotificationNow:notification];
            return;
        }
    }
    completionHandler(UNNotificationPresentationOptionAlert); // 需要執(zhí)行這個方法擂涛,選擇是否提醒用戶,有Badge聊记、Sound撒妈、Alert三種類型可以選擇設(shè)置
#else
#endif
}

- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler {
    NSDictionary * userInfo = response.notification.request.content.userInfo;
    NSDictionary *data = [NSDictionary dictionaryWithJsonString:userInfo[@"data"]];
//相關(guān)頁面跳轉(zhuǎn)在這個地方實現(xiàn)...
    
    if([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
#if __has_include("JPUSHService.h")
        [JPUSHService handleRemoteNotification:userInfo];
#else
#endif
    }
    completionHandler();  // 系統(tǒng)要求執(zhí)行這個方法
}

@end

以上是使用應(yīng)用啟動前這個服務(wù)的大致內(nèi)容。

為了避免這個頁面業(yè)務(wù)太多排监,針對不同的服務(wù)狰右,我們通過分類的形式進(jìn)行擴(kuò)展。
比如AppService(檢查版本更新服務(wù))

#import "SCLaunchService.h"

typedef void (^checkVersionBlock)(NSInteger isNewst); //0不是最新版本 1:是最新版本 3:接口異常
@interface SCLaunchService (AppService)

//版本更新
- (void)checkAppVersion:(checkVersionBlock)block;

@end
#import "SCLaunchService+AppService.h"
#import "SCBUApiRequest+SCAppVersion.h"
#import "SCVersionUpdateView.h"

@implementation SCLaunchService (AppService)

#pragma mark 檢測版本
- (void)checkAppVersion:(checkVersionBlock)block{
    //網(wǎng)絡(luò)請求調(diào)服務(wù)端接口 檢測是否需要強更
    [SCBUApiRequest checkAppVersion:@{} Success:^(SCBUApiResponse *response) {
        NSDictionary *result = response.responseObject;
//獲取本地版本號
        NSString *curVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];
//獲取服務(wù)端版本號
        NSString *serviceVersion = result[@"required_version"];
        int currVersionInt = [self convertVersionStrToInt:curVersion];
        int serviceVersionInt = [self convertVersionStrToInt:serviceVersion];
        if (currVersionInt<serviceVersionInt) {
//required_version 版本號 type更新類型(如果是force 那是就強更社露、非得話是暫不更新和立即更新)  result[@"update_content"] 更新說明
            SCVersionUpdateView *tipView = [[SCVersionUpdateView alloc] initWithVersion:result[@"required_version"] updateType:result[@"type"] updateCon:result[@"update_content"] updateUrl:result[@"update_url"]];
            [tipView show];
            block?block(0):nil;
        }else{
            block?block(1):nil;
        }
    } Failure:^(NSError *error) {
        block?block(2):nil;
    }];
}

//版本號轉(zhuǎn)換成整形  把版本號轉(zhuǎn)換成數(shù)值
- (int)convertVersionStrToInt:(NSString *)versionStr{
    __block int version = 0;
    [[versionStr componentsSeparatedByString:@"."] enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if (idx == 0) {
            version+= [obj intValue]*1000;
        }else if (idx==1){
            version+= [obj intValue]*100;
        }else if (idx==2){
            version+= [obj intValue];
        }
    }];
    return version;
}


@end

接口調(diào)用形式

@implementation SCBUApiRequest (SCAppVersion)
+ (void)checkAppVersion:(NSDictionary *)dic Success:(ApiSuccessBlock)success Failure:(ApiFailureBlock)failure{
    NSString *versionCheckUrl = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"sc_version_check"];
    if (versionCheckUrl) {
        NSString *url = [NSString stringWithFormat:@"%@%@",[SCEnvParameterConfig shareInstance].API_HOST_URL,versionCheckUrl];
        [SCBUApiRequest getJsonWithUrl:url param:nil Success:success failure:failure app:SCAppRequestTypeTSP];
    }

}

@end
屏幕快照 2019-03-25 下午3.33.49.png

彈出發(fā)現(xiàn)新版本View具體實現(xiàn)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末挟阻,一起剝皮案震驚了整個濱河市琼娘,隨后出現(xiàn)的幾起案子峭弟,更是在濱河造成了極大的恐慌,老刑警劉巖脱拼,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瞒瘸,死亡現(xiàn)場離奇詭異,居然都是意外死亡熄浓,警方通過查閱死者的電腦和手機情臭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來赌蔑,“玉大人俯在,你說我怎么就攤上這事⊥薰撸” “怎么了跷乐?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長趾浅。 經(jīng)常有香客問我愕提,道長馒稍,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任浅侨,我火速辦了婚禮纽谒,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘如输。我一直安慰自己鼓黔,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布挨决。 她就那樣靜靜地躺著请祖,像睡著了一般。 火紅的嫁衣襯著肌膚如雪脖祈。 梳的紋絲不亂的頭發(fā)上肆捕,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天,我揣著相機與錄音盖高,去河邊找鬼慎陵。 笑死,一個胖子當(dāng)著我的面吹牛喻奥,可吹牛的內(nèi)容都是我干的席纽。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼撞蚕,長吁一口氣:“原來是場噩夢啊……” “哼润梯!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起甥厦,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤纺铭,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后刀疙,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體舶赔,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年谦秧,在試婚紗的時候發(fā)現(xiàn)自己被綠了竟纳。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡疚鲤,死狀恐怖锥累,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情集歇,我是刑警寧澤桶略,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響删性,放射性物質(zhì)發(fā)生泄漏亏娜。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一蹬挺、第九天 我趴在偏房一處隱蔽的房頂上張望维贺。 院中可真熱鬧,春花似錦巴帮、人聲如沸溯泣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽垃沦。三九已至,卻和暖如春用押,著一層夾襖步出監(jiān)牢的瞬間肢簿,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工蜻拨, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留池充,地道東北人。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓缎讼,卻偏偏與公主長得像收夸,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子血崭,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,762評論 2 345