5
This commit is contained in:
@@ -10,6 +10,6 @@
|
||||
@interface AppDelegate : UIResponder <UIApplicationDelegate>
|
||||
|
||||
@property (nonatomic, strong) UIWindow *window;
|
||||
- (void)setupRootVC;
|
||||
- (void)toMainTabbarVC;
|
||||
@end
|
||||
|
||||
|
||||
@@ -94,13 +94,20 @@
|
||||
[self.window makeKeyAndVisible];
|
||||
|
||||
// 根据当前是否已登录决定入口:有 token 进主 TabBar,否则先进入登录页
|
||||
BOOL loggedIn = [[KBUserSessionManager shared] isLoggedIn];
|
||||
// BOOL loggedIn = [[KBUserSessionManager shared] isLoggedIn];
|
||||
UIViewController *rootVC = nil;
|
||||
if (loggedIn) {
|
||||
|
||||
rootVC = [[BaseTabBarController alloc] init];
|
||||
} else {
|
||||
rootVC = [[KBLoginVC alloc] init];
|
||||
|
||||
self.window.rootViewController = rootVC;
|
||||
}
|
||||
|
||||
- (void)toMainTabbarVC{
|
||||
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
|
||||
self.window.backgroundColor = [UIColor whiteColor];
|
||||
[self.window makeKeyAndVisible];
|
||||
UIViewController *rootVC = nil;
|
||||
rootVC = [[BaseTabBarController alloc] init];
|
||||
self.window.rootViewController = rootVC;
|
||||
}
|
||||
|
||||
@@ -209,35 +216,37 @@
|
||||
}
|
||||
|
||||
- (void)goLogin{
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.25 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
KBLoginPopView *view = [[KBLoginPopView alloc] initWithFrame:CGRectMake(0, 0, KB_SCREEN_WIDTH, KB_SCREEN_WIDTH)];
|
||||
// 创建并弹出
|
||||
LSTPopView *pop = [LSTPopView initWithCustomView:view
|
||||
parentView:nil
|
||||
popStyle:LSTPopStyleSmoothFromBottom
|
||||
dismissStyle:LSTDismissStyleSmoothToBottom];
|
||||
pop.hemStyle = LSTHemStyleBottom;
|
||||
pop.bgColor = [[UIColor blackColor] colorWithAlphaComponent:0.4];
|
||||
pop.isClickBgDismiss = YES; // 点击背景关闭
|
||||
pop.cornerRadius = 0; // 自定义 view 自处理圆角
|
||||
|
||||
__weak typeof(pop) weakPop = pop;
|
||||
view.appleLoginHandler = ^{
|
||||
[weakPop dismiss];
|
||||
// 交给 VM 统一处理 Apple 登录 + 服务端登录
|
||||
[[KBLoginVM shared] signInWithAppleFromViewController:KB_CURRENT_NAV completion:^(BOOL success, NSError * _Nullable error) {
|
||||
if (success) {
|
||||
[KBHUD showInfo:KBLocalized(@"Signed in successfully")];
|
||||
} else {
|
||||
NSString *msg = error.localizedDescription ?: KBLocalized(@"Sign-in failed");
|
||||
[KBHUD showInfo:msg];
|
||||
}
|
||||
}];
|
||||
};
|
||||
view.closeHandler = ^{ [weakPop dismiss]; };
|
||||
|
||||
[pop pop];
|
||||
});
|
||||
KBLoginVC *vc = [[KBLoginVC alloc] init];
|
||||
[KB_CURRENT_NAV pushViewController:vc animated:true];
|
||||
// dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.25 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
// KBLoginPopView *view = [[KBLoginPopView alloc] initWithFrame:CGRectMake(0, 0, KB_SCREEN_WIDTH, KB_SCREEN_WIDTH)];
|
||||
// // 创建并弹出
|
||||
// LSTPopView *pop = [LSTPopView initWithCustomView:view
|
||||
// parentView:nil
|
||||
// popStyle:LSTPopStyleSmoothFromBottom
|
||||
// dismissStyle:LSTDismissStyleSmoothToBottom];
|
||||
// pop.hemStyle = LSTHemStyleBottom;
|
||||
// pop.bgColor = [[UIColor blackColor] colorWithAlphaComponent:0.4];
|
||||
// pop.isClickBgDismiss = YES; // 点击背景关闭
|
||||
// pop.cornerRadius = 0; // 自定义 view 自处理圆角
|
||||
//
|
||||
// __weak typeof(pop) weakPop = pop;
|
||||
// view.appleLoginHandler = ^{
|
||||
// [weakPop dismiss];
|
||||
// // 交给 VM 统一处理 Apple 登录 + 服务端登录
|
||||
// [[KBLoginVM shared] signInWithAppleFromViewController:KB_CURRENT_NAV completion:^(BOOL success, NSError * _Nullable error) {
|
||||
// if (success) {
|
||||
// [KBHUD showInfo:KBLocalized(@"Signed in successfully")];
|
||||
// } else {
|
||||
// NSString *msg = error.localizedDescription ?: KBLocalized(@"Sign-in failed");
|
||||
// [KBHUD showInfo:msg];
|
||||
// }
|
||||
// }];
|
||||
// };
|
||||
// view.closeHandler = ^{ [weakPop dismiss]; };
|
||||
//
|
||||
// [pop pop];
|
||||
// });
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -164,6 +164,11 @@
|
||||
#pragma mark - Actions
|
||||
- (void)onTapBuyAction {
|
||||
// if (self.onTapBuy) { self.onTapBuy(); }
|
||||
// 未登录时先跳到登录页;登录后才允许进入会员购买页
|
||||
if (![KBUserSessionManager shared].isLoggedIn) {
|
||||
[[KBUserSessionManager shared] goLoginVC];
|
||||
return;
|
||||
}
|
||||
KBVipPay *vc = [[KBVipPay alloc] init];
|
||||
[KB_CURRENT_NAV pushViewController:vc animated:true];
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
// 背景
|
||||
@property (nonatomic, strong) UIImageView *bgImageView; // 整体背景图:login_bg_icon
|
||||
@property (nonatomic, strong) UIImageView *topRightImageView; // 顶部右侧装饰图:login_jianp_icon
|
||||
@property (nonatomic, strong) UIButton *backButton; // 顶部左侧返回按钮
|
||||
|
||||
// 底部白色容器(仅上圆角 26)
|
||||
@property (nonatomic, strong) UIView *contentContainerView;
|
||||
@@ -75,6 +76,14 @@
|
||||
make.edges.equalTo(self.view);
|
||||
}];
|
||||
|
||||
// 顶部左侧返回按钮
|
||||
[self.view addSubview:self.backButton];
|
||||
[self.backButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(self.view).offset(16);
|
||||
make.top.equalTo(self.view).offset(KB_StatusBarHeight() + 8);
|
||||
make.width.height.mas_equalTo(32);
|
||||
}];
|
||||
|
||||
// 顶部右侧装饰图
|
||||
[self.view addSubview:self.topRightImageView];
|
||||
[self.topRightImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
@@ -165,7 +174,7 @@
|
||||
id<UIApplicationDelegate> appDelegate = UIApplication.sharedApplication.delegate;
|
||||
if ([appDelegate respondsToSelector:@selector(setupRootVC)]) {
|
||||
AppDelegate *delegate = (AppDelegate *)appDelegate;
|
||||
[delegate setupRootVC];
|
||||
[delegate toMainTabbarVC];
|
||||
}
|
||||
});
|
||||
} else {
|
||||
@@ -195,6 +204,15 @@
|
||||
KBLOG(@"onTapForgotPassword");
|
||||
}
|
||||
|
||||
- (void)onTapBack {
|
||||
// 与 BaseViewController 的返回逻辑保持一致:优先 pop,其次 dismiss
|
||||
if (self.navigationController && self.navigationController.viewControllers.count > 1) {
|
||||
[self.navigationController popViewControllerAnimated:YES];
|
||||
} else if (self.presentingViewController) {
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Lazy UI
|
||||
|
||||
- (UIImageView *)bgImageView {
|
||||
@@ -223,6 +241,21 @@
|
||||
return _contentContainerView;
|
||||
}
|
||||
|
||||
- (UIButton *)backButton {
|
||||
if (!_backButton) {
|
||||
_backButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
UIImage *img = [UIImage imageNamed:@"back"];
|
||||
if (!img) { img = [UIImage imageNamed:@"back_black_icon"]; }
|
||||
if (img) {
|
||||
[_backButton setImage:img forState:UIControlStateNormal];
|
||||
}
|
||||
_backButton.adjustsImageWhenHighlighted = YES;
|
||||
_backButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
|
||||
[_backButton addTarget:self action:@selector(onTapBack) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _backButton;
|
||||
}
|
||||
|
||||
- (UILabel *)titleLabel {
|
||||
if (!_titleLabel) {
|
||||
_titleLabel = [UILabel new];
|
||||
|
||||
@@ -36,6 +36,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
/// 退出登录:清 Keychain + 本地缓存
|
||||
- (void)logout;
|
||||
|
||||
- (void)goLoginVC;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#import "KBUser.h"
|
||||
#import "KBConfig.h"
|
||||
#import <MJExtension/MJExtension.h>
|
||||
|
||||
#import "KBLoginVC.h"
|
||||
/// App Group 里的用户缓存 key
|
||||
static NSString * const kKBSessionUserStoreKey = @"KBSession.currentUser";
|
||||
/// “本次安装是否已初始化”标记 key(用来识别卸载重装)
|
||||
@@ -58,14 +58,17 @@ static NSString * const kKBSessionInstallFlagKey = @"KBSession.installInitialize
|
||||
if (self.didBootstrap) return;
|
||||
self.didBootstrap = YES;
|
||||
|
||||
BOOL hasInitializedThisInstall = [self.defaults boolForKey:kKBSessionInstallFlagKey];
|
||||
// 使用本 App 的 standardUserDefaults 记录“本次安装是否已初始化”。
|
||||
// 这样在卸载重装后,这个标记会被系统清空,从而触发一次性清理旧的 Keychain token。
|
||||
NSUserDefaults *installDefaults = [NSUserDefaults standardUserDefaults];
|
||||
BOOL hasInitializedThisInstall = [installDefaults boolForKey:kKBSessionInstallFlagKey];
|
||||
|
||||
KBAuthManager *auth = [KBAuthManager shared]; // 内部会 reloadFromKeychain
|
||||
|
||||
if (!hasInitializedThisInstall) {
|
||||
// 说明是“卸载重装后的第一次运行”(或者真正第一次安装)
|
||||
[self.defaults setBool:YES forKey:kKBSessionInstallFlagKey];
|
||||
[self.defaults synchronize];
|
||||
[installDefaults setBool:YES forKey:kKBSessionInstallFlagKey];
|
||||
[installDefaults synchronize];
|
||||
|
||||
// 若此时 Keychain 里已有 token,多半是上一次安装遗留的;按你的需求清掉
|
||||
if (auth.current.accessToken.length > 0) {
|
||||
@@ -160,4 +163,9 @@ static NSString * const kKBSessionInstallFlagKey = @"KBSession.installInitialize
|
||||
}
|
||||
}
|
||||
|
||||
- (void)goLoginVC{
|
||||
KBLoginVC *vc = [[KBLoginVC alloc] init];
|
||||
[KB_CURRENT_NAV pushViewController:vc animated:true];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
[[KBNetworkManager shared] GET:API_LOGOUT
|
||||
parameters:nil
|
||||
headers:nil
|
||||
autoShowBusinessError:NO
|
||||
completion:^(NSDictionary *jsonOrData, NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
||||
// 不管成功失败,都先把 HUD 收掉
|
||||
[KBHUD dismiss];
|
||||
@@ -34,9 +35,9 @@
|
||||
// 回到登录 / 主界面
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
id<UIApplicationDelegate> appDelegate = UIApplication.sharedApplication.delegate;
|
||||
if ([appDelegate respondsToSelector:@selector(setupRootVC)]) {
|
||||
if ([appDelegate respondsToSelector:@selector(toMainTabbarVC)]) {
|
||||
AppDelegate *delegate = (AppDelegate *)appDelegate;
|
||||
[delegate setupRootVC];
|
||||
[delegate toMainTabbarVC];
|
||||
}
|
||||
});
|
||||
}];
|
||||
|
||||
@@ -48,6 +48,13 @@ typedef void(^KBNetworkDataCompletion)(NSData *_Nullable data,
|
||||
@property (nonatomic, assign) NSTimeInterval timeout;
|
||||
|
||||
/// GET 请求,parameters 会拼到 URL 上
|
||||
- (nullable NSURLSessionDataTask *)GET:(NSString *)path
|
||||
parameters:(nullable NSDictionary *)parameters
|
||||
headers:(nullable NSDictionary<NSString *, NSString *> *)headers
|
||||
autoShowBusinessError:(BOOL)autoShowBusinessError
|
||||
completion:(KBNetworkCompletion)completion;
|
||||
|
||||
/// 兼容旧调用:默认 autoShowBusinessError = YES
|
||||
- (nullable NSURLSessionDataTask *)GET:(NSString *)path
|
||||
parameters:(nullable NSDictionary *)parameters
|
||||
headers:(nullable NSDictionary<NSString *, NSString *> *)headers
|
||||
@@ -60,6 +67,13 @@ typedef void(^KBNetworkDataCompletion)(NSData *_Nullable data,
|
||||
completion:(KBNetworkDataCompletion)completion;
|
||||
|
||||
/// POST JSON 请求,jsonBody 会以 application/json 发送
|
||||
- (nullable NSURLSessionDataTask *)POST:(NSString *)path
|
||||
jsonBody:(nullable id)jsonBody
|
||||
headers:(nullable NSDictionary<NSString *, NSString *> *)headers
|
||||
autoShowBusinessError:(BOOL)autoShowBusinessError
|
||||
completion:(KBNetworkCompletion)completion;
|
||||
|
||||
/// 兼容旧调用:默认 autoShowBusinessError = YES
|
||||
- (nullable NSURLSessionDataTask *)POST:(NSString *)path
|
||||
jsonBody:(nullable id)jsonBody
|
||||
headers:(nullable NSDictionary<NSString *, NSString *> *)headers
|
||||
|
||||
@@ -53,11 +53,14 @@ NSErrorDomain const KBNetworkErrorDomain = @"com.company.keyboard.network";
|
||||
return self;
|
||||
}
|
||||
|
||||
#
|
||||
#pragma mark - Public
|
||||
|
||||
// JSON GET:可控制业务错误是否由内部弹出
|
||||
- (NSURLSessionDataTask *)GET:(NSString *)path
|
||||
parameters:(NSDictionary *)parameters
|
||||
headers:(NSDictionary<NSString *,NSString *> *)headers
|
||||
autoShowBusinessError:(BOOL)autoShowBusinessError
|
||||
completion:(KBNetworkCompletion)completion {
|
||||
NSLog(@"[KBNetworkManager] GET called, enabled=%d, path=%@", self.isEnabled, path);
|
||||
if (![self ensureEnabled:completion]) return nil;
|
||||
@@ -84,14 +87,30 @@ NSErrorDomain const KBNetworkErrorDomain = @"com.company.keyboard.network";
|
||||
req.allHTTPHeaderFields ?: @{},
|
||||
paramStr);
|
||||
#endif
|
||||
return [self startJSONTaskWithRequest:req completion:completion];
|
||||
return [self startJSONTaskWithRequest:req
|
||||
autoShowBusinessError:autoShowBusinessError
|
||||
completion:completion];
|
||||
}
|
||||
|
||||
// 默认 GET:自动弹业务错误
|
||||
- (NSURLSessionDataTask *)GET:(NSString *)path
|
||||
parameters:(NSDictionary *)parameters
|
||||
headers:(NSDictionary<NSString *,NSString *> *)headers
|
||||
completion:(KBNetworkCompletion)completion {
|
||||
return [self GET:path
|
||||
parameters:parameters
|
||||
headers:headers
|
||||
autoShowBusinessError:YES
|
||||
completion:completion];
|
||||
}
|
||||
|
||||
// JSON POST:可控制业务错误是否由内部弹出
|
||||
- (NSURLSessionDataTask *)POST:(NSString *)path
|
||||
jsonBody:(id)jsonBody
|
||||
headers:(NSDictionary<NSString *,NSString *> *)headers
|
||||
autoShowBusinessError:(BOOL)autoShowBusinessError
|
||||
completion:(KBNetworkCompletion)completion {
|
||||
NSLog(@"=====");
|
||||
NSLog(@"[KBNetworkManager] POST called, enabled=%d, path=%@", self.isEnabled, path);
|
||||
if (![self ensureEnabled:completion]) return nil;
|
||||
NSString *urlString = [self buildURLStringWithPath:path];
|
||||
if (!urlString) { [self fail:KBNetworkErrorInvalidURL completion:completion]; return nil; }
|
||||
@@ -113,7 +132,21 @@ NSErrorDomain const KBNetworkErrorDomain = @"com.company.keyboard.network";
|
||||
req.allHTTPHeaderFields ?: @{},
|
||||
bodyStr);
|
||||
#endif
|
||||
return [self startJSONTaskWithRequest:req completion:completion];
|
||||
return [self startJSONTaskWithRequest:req
|
||||
autoShowBusinessError:autoShowBusinessError
|
||||
completion:completion];
|
||||
}
|
||||
|
||||
// 默认 POST:自动弹业务错误
|
||||
- (NSURLSessionDataTask *)POST:(NSString *)path
|
||||
jsonBody:(id)jsonBody
|
||||
headers:(NSDictionary<NSString *,NSString *> *)headers
|
||||
completion:(KBNetworkCompletion)completion {
|
||||
return [self POST:path
|
||||
jsonBody:jsonBody
|
||||
headers:headers
|
||||
autoShowBusinessError:YES
|
||||
completion:completion];
|
||||
}
|
||||
|
||||
// 原始二进制 GET,用于下载 zip、图片等
|
||||
@@ -190,6 +223,7 @@ NSErrorDomain const KBNetworkErrorDomain = @"com.company.keyboard.network";
|
||||
}
|
||||
|
||||
- (NSURLSessionDataTask *)startJSONTaskWithRequest:(NSURLRequest *)req
|
||||
autoShowBusinessError:(BOOL)autoShowBusinessError
|
||||
completion:(KBNetworkCompletion)completion {
|
||||
NSLog(@"[KBNetworkManager] startAFTaskWithRequest: %@", req.URL.absoluteString);
|
||||
// 响应先用原始数据返回,再按 Content-Type 解析 JSON(与原实现一致)
|
||||
@@ -267,8 +301,13 @@ NSErrorDomain const KBNetworkErrorDomain = @"com.company.keyboard.network";
|
||||
NSInteger bizCode = KBBizCodeFromJSONObject(dict);
|
||||
if (bizCode != NSNotFound && bizCode != KBBizCodeSuccess) {
|
||||
// 非成功业务 code:执行通用处理(如 token 失效)并通过 error 方式回调
|
||||
[self kb_handleBizCode:bizCode json:dict response:response];
|
||||
NSString *msg = KBBizMessageFromJSONObject(json) ?: KBLocalized(@"Server error");
|
||||
BOOL handledByAuth = [self kb_handleBizCode:bizCode json:dict response:response];
|
||||
NSString *msg = KBBizMessageFromJSONObject(dict) ?: KBLocalized(@"Server error");
|
||||
if (autoShowBusinessError && !handledByAuth) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[KBHUD showInfo:msg];
|
||||
});
|
||||
}
|
||||
NSError *bizErr = [NSError errorWithDomain:KBNetworkErrorDomain
|
||||
code:KBNetworkErrorBusiness
|
||||
userInfo:@{
|
||||
@@ -328,8 +367,9 @@ NSErrorDomain const KBNetworkErrorDomain = @"com.company.keyboard.network";
|
||||
|
||||
#pragma mark - Private helpers
|
||||
|
||||
/// 处理通用业务 code(token 失效、被踢下线等)
|
||||
- (void)kb_handleBizCode:(NSInteger)bizCode
|
||||
/// 处理通用业务 code(token 失效、被踢下线等);
|
||||
/// 返回 YES 表示该 code 已在此处消费(例如已清理登录态并提示),外部无需再提示。
|
||||
- (BOOL)kb_handleBizCode:(NSInteger)bizCode
|
||||
json:(id)json
|
||||
response:(NSURLResponse *)response {
|
||||
switch (bizCode) {
|
||||
@@ -361,10 +401,12 @@ NSErrorDomain const KBNetworkErrorDomain = @"com.company.keyboard.network";
|
||||
object:nil
|
||||
userInfo:info];
|
||||
});
|
||||
return YES;
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)fail:(KBNetworkError)code completion:(KBNetworkCompletion)completion {
|
||||
|
||||
Reference in New Issue
Block a user