1
This commit is contained in:
@@ -25,6 +25,8 @@
|
|||||||
#define API_RESET_PWD @"/user/resetPassWord" // 重置密码
|
#define API_RESET_PWD @"/user/resetPassWord" // 重置密码
|
||||||
#define API_USER_FEEDBACK @"/user/feedback" // 提交反馈
|
#define API_USER_FEEDBACK @"/user/feedback" // 提交反馈
|
||||||
|
|
||||||
|
#define API_APP_CHECK_UPDATE @"/appVersions/checkUpdate" // 检查更新
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define API_LOGOUT @"/user/logout" // 退出登录
|
#define API_LOGOUT @"/user/logout" // 退出登录
|
||||||
|
|||||||
@@ -19,10 +19,10 @@ FOUNDATION_EXPORT KBLanguageCode const KBLanguageCodeEnglish; // @"en"
|
|||||||
FOUNDATION_EXPORT KBLanguageCode const KBLanguageCodeSimplifiedChinese; // @"zh-Hans"
|
FOUNDATION_EXPORT KBLanguageCode const KBLanguageCodeSimplifiedChinese; // @"zh-Hans"
|
||||||
FOUNDATION_EXPORT KBLanguageCode const KBLanguageCodeTraditionalChinese; // @"zh-Hant"
|
FOUNDATION_EXPORT KBLanguageCode const KBLanguageCodeTraditionalChinese; // @"zh-Hant"
|
||||||
FOUNDATION_EXPORT KBLanguageCode const KBLanguageCodeSpanish; // @"es"
|
FOUNDATION_EXPORT KBLanguageCode const KBLanguageCodeSpanish; // @"es"
|
||||||
FOUNDATION_EXPORT KBLanguageCode const KBLanguageCodePortuguese; // @"pt"
|
FOUNDATION_EXPORT KBLanguageCode const KBLanguageCodePortuguese; // @"pt-PT"
|
||||||
FOUNDATION_EXPORT KBLanguageCode const KBLanguageCodeIndonesian; // @"id"
|
FOUNDATION_EXPORT KBLanguageCode const KBLanguageCodeIndonesian; // @"id"
|
||||||
|
|
||||||
/// 默认支持的语言列表(当前:en / zh-Hans / zh-Hant / es / pt / id)
|
/// 默认支持的语言列表(当前:en / zh-Hans / zh-Hant / es / pt-PT / id)
|
||||||
FOUNDATION_EXPORT NSArray<KBLanguageCode> *KBDefaultSupportedLanguageCodes(void);
|
FOUNDATION_EXPORT NSArray<KBLanguageCode> *KBDefaultSupportedLanguageCodes(void);
|
||||||
|
|
||||||
/// 当前语言变更通知(不附带 userInfo)
|
/// 当前语言变更通知(不附带 userInfo)
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ KBLanguageCode const KBLanguageCodeEnglish = @"en";
|
|||||||
KBLanguageCode const KBLanguageCodeSimplifiedChinese = @"zh-Hans";
|
KBLanguageCode const KBLanguageCodeSimplifiedChinese = @"zh-Hans";
|
||||||
KBLanguageCode const KBLanguageCodeTraditionalChinese = @"zh-Hant";
|
KBLanguageCode const KBLanguageCodeTraditionalChinese = @"zh-Hant";
|
||||||
KBLanguageCode const KBLanguageCodeSpanish = @"es";
|
KBLanguageCode const KBLanguageCodeSpanish = @"es";
|
||||||
KBLanguageCode const KBLanguageCodePortuguese = @"pt";
|
KBLanguageCode const KBLanguageCodePortuguese = @"pt-PT";
|
||||||
KBLanguageCode const KBLanguageCodeIndonesian = @"id";
|
KBLanguageCode const KBLanguageCodeIndonesian = @"id";
|
||||||
|
|
||||||
/// 默认支持语言列表(集中配置)
|
/// 默认支持语言列表(集中配置)
|
||||||
@@ -94,7 +94,7 @@ static inline NSMutableDictionary *KBLocBaseKCQuery(void) {
|
|||||||
if (code.length == 0) return; // 忽略空值
|
if (code.length == 0) return; // 忽略空值
|
||||||
if ([code isEqualToString:self.currentLanguageCode]) return; // 无变更
|
if ([code isEqualToString:self.currentLanguageCode]) return; // 无变更
|
||||||
[self applyLanguage:code];
|
[self applyLanguage:code];
|
||||||
if (persist) { [[self class] kc_write:code]; } // 需同步到 App/扩展
|
if (persist) { [[self class] kc_write:self.currentLanguageCode]; } // 需同步到 App/扩展
|
||||||
[[NSNotificationCenter defaultCenter] postNotificationName:KBLocalizationDidChangeNotification object:nil];
|
[[NSNotificationCenter defaultCenter] postNotificationName:KBLocalizationDidChangeNotification object:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,12 +160,16 @@ static inline NSMutableDictionary *KBLocBaseKCQuery(void) {
|
|||||||
#pragma mark - 内部实现
|
#pragma mark - 内部实现
|
||||||
|
|
||||||
- (void)applyLanguage:(NSString *)code {
|
- (void)applyLanguage:(NSString *)code {
|
||||||
_currentLanguageCode = [code copy];
|
NSString *normalizedCode = code;
|
||||||
|
if ([normalizedCode.lowercaseString isEqualToString:@"pt"]) {
|
||||||
|
normalizedCode = @"pt-PT";
|
||||||
|
}
|
||||||
|
_currentLanguageCode = [normalizedCode copy];
|
||||||
// 基于当前 Target(App 或扩展)的主 bundle 加载 .lproj 资源
|
// 基于当前 Target(App 或扩展)的主 bundle 加载 .lproj 资源
|
||||||
NSString *path = [NSBundle.mainBundle pathForResource:code ofType:@"lproj"];
|
NSString *path = [NSBundle.mainBundle pathForResource:normalizedCode ofType:@"lproj"];
|
||||||
if (!path) {
|
if (!path) {
|
||||||
// 尝试去区域后缀:如 en-GB -> en
|
// 尝试去区域后缀:如 en-GB -> en
|
||||||
NSString *shortCode = [[code componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"-_"]] firstObject];
|
NSString *shortCode = [[normalizedCode componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"-_"]] firstObject];
|
||||||
if (shortCode.length > 0) {
|
if (shortCode.length > 0) {
|
||||||
path = [NSBundle.mainBundle pathForResource:shortCode ofType:@"lproj"];
|
path = [NSBundle.mainBundle pathForResource:shortCode ofType:@"lproj"];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ static NSTimeInterval const kKBSubscriptionPrefillTTL = 10 * 60.0;
|
|||||||
|
|
||||||
@interface AppDelegate () <KBAppUpdateViewDelegate>
|
@interface AppDelegate () <KBAppUpdateViewDelegate>
|
||||||
@property (nonatomic, strong) LSTPopView *appUpdatePopView;
|
@property (nonatomic, strong) LSTPopView *appUpdatePopView;
|
||||||
|
@property (nonatomic, copy) NSString *appUpdateURLString;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation AppDelegate
|
@implementation AppDelegate
|
||||||
@@ -87,31 +88,220 @@ static NSTimeInterval const kKBSubscriptionPrefillTTL = 10 * 60.0;
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)kb_requestAppUpdateAndPresentIfNeeded {
|
- (void)kb_requestAppUpdateAndPresentIfNeeded {
|
||||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
__weak typeof(self) weakSelf = self;
|
||||||
if (self.appUpdatePopView) { return; }
|
[[KBLoginVM shared] checkAppUpdateWithCompletion:^(NSDictionary * _Nullable data, NSError * _Nullable error) {
|
||||||
CGFloat width = KBFit(323.0);
|
if (error) { return; }
|
||||||
CGFloat height = KBFit(390.0);
|
if (![data isKindOfClass:NSDictionary.class]) { return; }
|
||||||
KBAppUpdateView *view = [[KBAppUpdateView alloc] initWithFrame:CGRectMake(0, 0, width, height)];
|
NSDictionary *payload = data[@"data"];
|
||||||
view.backgroundImageName = @"app_update_bg";
|
if (![payload isKindOfClass:NSDictionary.class]) {
|
||||||
view.delegate = self;
|
payload = (NSDictionary *)data;
|
||||||
LSTPopView *pop = [LSTPopView initWithCustomView:view
|
}
|
||||||
parentView:nil
|
if (![payload isKindOfClass:NSDictionary.class]) { return; }
|
||||||
popStyle:LSTPopStyleScale
|
if (![weakSelf kb_shouldPresentAppUpdateWithData:payload]) { return; }
|
||||||
dismissStyle:LSTDismissStyleScale];
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
pop.hemStyle = LSTHemStyleCenter;
|
[weakSelf kb_presentAppUpdateWithData:payload];
|
||||||
pop.bgColor = [[UIColor blackColor] colorWithAlphaComponent:0.4];
|
});
|
||||||
pop.isClickBgDismiss = NO;
|
}];
|
||||||
pop.cornerRadius = 0;
|
}
|
||||||
self.appUpdatePopView = pop;
|
|
||||||
[pop pop];
|
- (void)kb_presentAppUpdateWithData:(NSDictionary *)data {
|
||||||
});
|
if (self.appUpdatePopView) { return; }
|
||||||
|
CGFloat width = KBFit(323.0);
|
||||||
|
CGFloat height = KBFit(390.0);
|
||||||
|
KBAppUpdateView *view = [[KBAppUpdateView alloc] initWithFrame:CGRectMake(0, 0, width, height)];
|
||||||
|
view.backgroundImageName = @"app_update_bg";
|
||||||
|
view.delegate = self;
|
||||||
|
NSString *title = [self kb_stringForKeys:@[@"title", @"updateTitle", @"headline", @"appTitle"] inDictionary:data];
|
||||||
|
if (title.length > 0) {
|
||||||
|
view.titleText = title;
|
||||||
|
}
|
||||||
|
NSString *versionName = [self kb_stringForKeys:@[@"versionName", @"latestVersionName", @"newVersionName", @"version", @"latestVersion"] inDictionary:data];
|
||||||
|
if (versionName.length > 0) {
|
||||||
|
if (![versionName hasPrefix:@"V"] && ![versionName hasPrefix:@"v"]) {
|
||||||
|
versionName = [NSString stringWithFormat:@"V%@", versionName];
|
||||||
|
}
|
||||||
|
view.versionText = versionName;
|
||||||
|
}
|
||||||
|
NSString *contentTitle = [self kb_stringForKeys:@[@"contentTitle", @"updateContentTitle", @"descTitle", @"updateDescTitle"] inDictionary:data];
|
||||||
|
if (contentTitle.length > 0) {
|
||||||
|
view.contentTitleText = contentTitle;
|
||||||
|
}
|
||||||
|
id contentObj = [self kb_objectForKeys:@[@"contentItems", @"updateContent", @"updateDesc", @"description", @"desc", @"content"] inDictionary:data];
|
||||||
|
NSArray<NSString *> *items = [self kb_contentItemsFromObject:contentObj];
|
||||||
|
if (items.count > 0) {
|
||||||
|
view.contentItems = items;
|
||||||
|
}
|
||||||
|
NSString *buttonTitle = [self kb_stringForKeys:@[@"upgradeButtonTitle", @"upgradeButtonText", @"buttonText", @"buttonTitle"] inDictionary:data];
|
||||||
|
if (buttonTitle.length > 0) {
|
||||||
|
view.upgradeButtonTitle = buttonTitle;
|
||||||
|
}
|
||||||
|
self.appUpdateURLString = [self kb_stringForKeys:@[@"downloadUrl", @"downloadURL", @"url", @"appStoreUrl", @"appStoreURL", @"installUrl", @"upgradeUrl"] inDictionary:data];
|
||||||
|
|
||||||
|
LSTPopView *pop = [LSTPopView initWithCustomView:view
|
||||||
|
parentView:nil
|
||||||
|
popStyle:LSTPopStyleScale
|
||||||
|
dismissStyle:LSTDismissStyleScale];
|
||||||
|
pop.hemStyle = LSTHemStyleCenter;
|
||||||
|
pop.bgColor = [[UIColor blackColor] colorWithAlphaComponent:0.4];
|
||||||
|
pop.isClickBgDismiss = NO;
|
||||||
|
pop.cornerRadius = 0;
|
||||||
|
self.appUpdatePopView = pop;
|
||||||
|
[pop pop];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)kb_shouldPresentAppUpdateWithData:(NSDictionary *)data {
|
||||||
|
NSArray<NSString *> *flagKeys = @[@"needUpdate", @"hasUpdate", @"shouldUpdate", @"needUpgrade", @"hasUpgrade", @"update", @"isUpdate"];
|
||||||
|
for (NSString *key in flagKeys) {
|
||||||
|
id obj = data[key];
|
||||||
|
if (obj && ![obj isKindOfClass:NSNull.class] &&
|
||||||
|
([obj isKindOfClass:NSNumber.class] || [obj isKindOfClass:NSString.class])) {
|
||||||
|
return [self kb_boolValueFromObject:obj];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NSArray<NSString *> *typeKeys = @[@"updateType", @"upgradeType", @"updateMode"];
|
||||||
|
for (NSString *key in typeKeys) {
|
||||||
|
id obj = data[key];
|
||||||
|
if (obj && ![obj isKindOfClass:NSNull.class] &&
|
||||||
|
([obj isKindOfClass:NSNumber.class] || [obj isKindOfClass:NSString.class])) {
|
||||||
|
NSInteger typeValue = [self kb_integerValueFromObject:obj];
|
||||||
|
return typeValue > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NSInteger localCode = [self kb_localVersionCode];
|
||||||
|
NSArray<NSString *> *codeKeys = @[@"versionCode", @"latestVersionCode", @"newVersionCode", @"latestCode", @"buildNumber"];
|
||||||
|
for (NSString *key in codeKeys) {
|
||||||
|
id obj = data[key];
|
||||||
|
if (obj && ![obj isKindOfClass:NSNull.class]) {
|
||||||
|
NSInteger remoteCode = [self kb_versionCodeFromObject:obj];
|
||||||
|
if (remoteCode > 0 && localCode > 0) {
|
||||||
|
return remoteCode > localCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (nullable id)kb_objectForKeys:(NSArray<NSString *> *)keys inDictionary:(NSDictionary *)dict {
|
||||||
|
for (NSString *key in keys) {
|
||||||
|
id obj = dict[key];
|
||||||
|
if (obj && ![obj isKindOfClass:NSNull.class]) {
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (nullable NSString *)kb_stringForKeys:(NSArray<NSString *> *)keys inDictionary:(NSDictionary *)dict {
|
||||||
|
id obj = [self kb_objectForKeys:keys inDictionary:dict];
|
||||||
|
return [self kb_stringFromObject:obj];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (nullable NSString *)kb_stringFromObject:(id)obj {
|
||||||
|
if ([obj isKindOfClass:NSString.class]) { return (NSString *)obj; }
|
||||||
|
if ([obj respondsToSelector:@selector(stringValue)]) { return [obj stringValue]; }
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)kb_boolValueFromObject:(id)obj {
|
||||||
|
if ([obj isKindOfClass:NSNumber.class]) { return ((NSNumber *)obj).boolValue; }
|
||||||
|
if ([obj isKindOfClass:NSString.class]) {
|
||||||
|
NSString *lower = [(NSString *)obj lowercaseString];
|
||||||
|
if ([lower isEqualToString:@"true"] || [lower isEqualToString:@"yes"]) { return YES; }
|
||||||
|
if ([lower isEqualToString:@"false"] || [lower isEqualToString:@"no"]) { return NO; }
|
||||||
|
return lower.integerValue != 0;
|
||||||
|
}
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSInteger)kb_integerValueFromObject:(id)obj {
|
||||||
|
if ([obj respondsToSelector:@selector(integerValue)]) { return [obj integerValue]; }
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSInteger)kb_versionCodeFromObject:(id)obj {
|
||||||
|
if ([obj isKindOfClass:NSString.class]) {
|
||||||
|
NSString *digits = [self kb_digitsOnlyStringFromString:obj];
|
||||||
|
if (digits.length > 0) { return digits.longLongValue; }
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if ([obj respondsToSelector:@selector(longLongValue)]) {
|
||||||
|
return (NSInteger)[obj longLongValue];
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSArray<NSString *> *)kb_contentItemsFromObject:(id)obj {
|
||||||
|
if ([obj isKindOfClass:NSArray.class]) {
|
||||||
|
NSMutableArray<NSString *> *items = [NSMutableArray array];
|
||||||
|
for (id item in (NSArray *)obj) {
|
||||||
|
NSString *text = [self kb_stringFromObject:item];
|
||||||
|
if (text.length > 0) {
|
||||||
|
[items addObject:text];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
if ([obj isKindOfClass:NSString.class]) {
|
||||||
|
NSString *text = [(NSString *)obj stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||||
|
if (text.length == 0) { return @[]; }
|
||||||
|
NSCharacterSet *splitSet = [NSCharacterSet characterSetWithCharactersInString:@"\n;"];
|
||||||
|
NSArray<NSString *> *parts = [text componentsSeparatedByCharactersInSet:splitSet];
|
||||||
|
NSMutableArray<NSString *> *items = [NSMutableArray array];
|
||||||
|
for (NSString *part in parts) {
|
||||||
|
NSString *trimmed = [part stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||||
|
if (trimmed.length > 0) {
|
||||||
|
[items addObject:trimmed];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return items.count > 0 ? items : @[text];
|
||||||
|
}
|
||||||
|
return @[];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSInteger)kb_localVersionCode {
|
||||||
|
NSString *buildNumber = [self kb_stringFromObject:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]];
|
||||||
|
NSString *shortVersion = [self kb_stringFromObject:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"]];
|
||||||
|
NSString *digits = [self kb_digitsOnlyStringFromString:buildNumber];
|
||||||
|
if (digits.length == 0) {
|
||||||
|
digits = [self kb_digitsOnlyStringFromString:shortVersion];
|
||||||
|
}
|
||||||
|
if (digits.length == 0) { return 0; }
|
||||||
|
return digits.longLongValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (nullable NSString *)kb_digitsOnlyStringFromString:(nullable NSString *)string {
|
||||||
|
if (![string isKindOfClass:NSString.class] || string.length == 0) { return nil; }
|
||||||
|
NSCharacterSet *set = [NSCharacterSet decimalDigitCharacterSet];
|
||||||
|
NSMutableString *digits = [NSMutableString string];
|
||||||
|
for (NSUInteger i = 0; i < string.length; i++) {
|
||||||
|
unichar c = [string characterAtIndex:i];
|
||||||
|
if ([set characterIsMember:c]) {
|
||||||
|
[digits appendFormat:@"%C", c];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return digits;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - KBAppUpdateViewDelegate
|
#pragma mark - KBAppUpdateViewDelegate
|
||||||
|
|
||||||
- (void)appUpdateViewDidTapUpgrade:(KBAppUpdateView *)view {
|
- (void)appUpdateViewDidTapUpgrade:(KBAppUpdateView *)view {
|
||||||
|
NSString *urlString = self.appUpdateURLString;
|
||||||
|
if (urlString.length > 0) {
|
||||||
|
NSURL *url = [NSURL URLWithString:urlString];
|
||||||
|
if (url) {
|
||||||
|
UIApplication *app = [UIApplication sharedApplication];
|
||||||
|
if ([app canOpenURL:url]) {
|
||||||
|
if (@available(iOS 10.0, *)) {
|
||||||
|
[app openURL:url options:@{} completionHandler:nil];
|
||||||
|
} else {
|
||||||
|
[app openURL:url];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
[self.appUpdatePopView dismiss];
|
[self.appUpdatePopView dismiss];
|
||||||
self.appUpdatePopView = nil;
|
self.appUpdatePopView = nil;
|
||||||
|
self.appUpdateURLString = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)applicationDidBecomeActive:(UIApplication *)application{
|
- (void)applicationDidBecomeActive:(UIApplication *)application{
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||||||
typedef void(^KBLoginCompletion)(BOOL success, NSError * _Nullable error);
|
typedef void(^KBLoginCompletion)(BOOL success, NSError * _Nullable error);
|
||||||
typedef void(^KBRegisterCompletion)(BOOL success, NSError * _Nullable error);
|
typedef void(^KBRegisterCompletion)(BOOL success, NSError * _Nullable error);
|
||||||
typedef void(^KBVerifyMailCompletion)(BOOL success, NSError * _Nullable error);
|
typedef void(^KBVerifyMailCompletion)(BOOL success, NSError * _Nullable error);
|
||||||
|
typedef void(^KBAppUpdateCompletion)(NSDictionary * _Nullable data, NSError * _Nullable error);
|
||||||
|
|
||||||
@interface KBLoginVM : NSObject
|
@interface KBLoginVM : NSObject
|
||||||
|
|
||||||
@@ -42,6 +43,9 @@ typedef void(^KBVerifyMailCompletion)(BOOL success, NSError * _Nullable error);
|
|||||||
/// 是否已登录:由 KBAuthManager 判断(是否存在有效 token)
|
/// 是否已登录:由 KBAuthManager 判断(是否存在有效 token)
|
||||||
- (BOOL)isLoggedIn;
|
- (BOOL)isLoggedIn;
|
||||||
|
|
||||||
|
/// 检查是否需要更新
|
||||||
|
- (void)checkAppUpdateWithCompletion:(KBAppUpdateCompletion)completion;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
NS_ASSUME_NONNULL_END
|
||||||
|
|||||||
@@ -164,6 +164,15 @@
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 检查更新
|
||||||
|
- (void)checkAppUpdateWithCompletion:(KBAppUpdateCompletion)completion {
|
||||||
|
NSDictionary *params = [self kb_appUpdateParams];
|
||||||
|
[[KBNetworkManager shared] POST:API_APP_CHECK_UPDATE jsonBody:params headers:nil autoShowBusinessError:NO completion:^(NSDictionary * _Nullable jsonOrData, NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
||||||
|
if (error) { if (completion) completion(nil, error); return; }
|
||||||
|
if (completion) completion(jsonOrData, nil);
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - Private
|
#pragma mark - Private
|
||||||
|
|
||||||
- (void)kb_syncKeyboardCharactersAfterLogin {
|
- (void)kb_syncKeyboardCharactersAfterLogin {
|
||||||
@@ -228,4 +237,63 @@
|
|||||||
return @(value);
|
return @(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSDictionary *)kb_appUpdateParams {
|
||||||
|
NSMutableDictionary *params = [NSMutableDictionary dictionary];
|
||||||
|
params[@"appId"] = @"main";
|
||||||
|
params[@"platform"] = @"ios";
|
||||||
|
params[@"channel"] = @"AppStore";
|
||||||
|
NSString *shortVersion = [self kb_bundleShortVersion];
|
||||||
|
if (shortVersion.length) {
|
||||||
|
params[@"clientVersionName"] = shortVersion;
|
||||||
|
}
|
||||||
|
NSString *buildNumber = [self kb_bundleBuildNumber];
|
||||||
|
if (buildNumber.length) {
|
||||||
|
params[@"buildNumber"] = buildNumber;
|
||||||
|
}
|
||||||
|
NSNumber *versionCode = [self kb_versionCodeFromBuildNumber:buildNumber shortVersion:shortVersion];
|
||||||
|
// if (versionCode) {
|
||||||
|
params[@"clientVersionCode"] = @1;
|
||||||
|
// }
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (nullable NSString *)kb_bundleShortVersion {
|
||||||
|
id obj = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
|
||||||
|
if ([obj isKindOfClass:NSString.class]) { return (NSString *)obj; }
|
||||||
|
if ([obj respondsToSelector:@selector(stringValue)]) { return [obj stringValue]; }
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (nullable NSString *)kb_bundleBuildNumber {
|
||||||
|
id obj = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"];
|
||||||
|
if ([obj isKindOfClass:NSString.class]) { return (NSString *)obj; }
|
||||||
|
if ([obj respondsToSelector:@selector(stringValue)]) { return [obj stringValue]; }
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (nullable NSNumber *)kb_versionCodeFromBuildNumber:(nullable NSString *)buildNumber
|
||||||
|
shortVersion:(nullable NSString *)shortVersion {
|
||||||
|
NSString *digits = [self kb_digitsOnlyStringFromString:buildNumber];
|
||||||
|
if (digits.length == 0) {
|
||||||
|
digits = [self kb_digitsOnlyStringFromString:shortVersion];
|
||||||
|
}
|
||||||
|
if (digits.length == 0) { return nil; }
|
||||||
|
long long value = digits.longLongValue;
|
||||||
|
if (value <= 0) { return nil; }
|
||||||
|
return @(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (nullable NSString *)kb_digitsOnlyStringFromString:(nullable NSString *)string {
|
||||||
|
if (![string isKindOfClass:NSString.class] || string.length == 0) { return nil; }
|
||||||
|
NSCharacterSet *set = [NSCharacterSet decimalDigitCharacterSet];
|
||||||
|
NSMutableString *digits = [NSMutableString string];
|
||||||
|
for (NSUInteger i = 0; i < string.length; i++) {
|
||||||
|
unichar c = [string characterAtIndex:i];
|
||||||
|
if ([set characterIsMember:c]) {
|
||||||
|
[digits appendFormat:@"%C", c];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return digits;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
Reference in New Issue
Block a user